Générer un point aléatoire dans un cercle (uniformément)


212

J'ai besoin de générer un point uniformément aléatoire dans un cercle de rayon R .

Je me rends compte qu'en choisissant simplement un angle uniformément aléatoire dans l'intervalle [0 ... 2π), et un rayon uniformément aléatoire dans l'intervalle (0 ... R ), je me retrouverais avec plus de points vers le centre, car pour deux donnés rayons, les points dans le plus petit rayon seront plus proches les uns des autres que pour les points dans le plus grand rayon.

J'ai trouvé une entrée de blog à ce sujet ici, mais je ne comprends pas son raisonnement. Je suppose que c'est correct, mais j'aimerais vraiment comprendre d'où il obtient (2 / R 2 ) × r et comment il dérive la solution finale.


Mise à jour: 7 ans après avoir posté cette question, je n'avais toujours pas reçu de réponse satisfaisante à la question réelle concernant les mathématiques derrière l'algorithme de racine carrée. J'ai donc passé une journée à rédiger une réponse moi-même. Lien vers ma réponse .


18
L'inconvénient de l'échantillonnage de rejet est-il vraiment un gros problème? Le nombre attendu d'essais requis est de 4 / π ≈ 1,27, et la probabilité que vous ayez besoin de plus de k essais est de (1-π / 4) ^ k. Pour k = 20 , c'est ≈ .00000000000004 et pour k = 50 c'est de l'ordre de 10 ^ {- 34}. Vous pouvez prendre ces cotes n'importe quel jour; vous ferez bien.
ShreevatsaR

3
En fait, l'échantillonnage de rejet offre une garantie de résiliation. Les chances sont infiniment faibles (pour être précis, nulles) que votre algorithme ne se terminera jamais.
Jared Nielsen

2
À mon avis, l'importance de l'inconvénient de l'échantillonnage par rejet est proportionnelle à la facilité d'utilisation d'une méthode d'échantillonnage qui évite le rejet. Dans ce cas, l'inconvénient est important car l'échantillonnage sans rejet est simple.
spex

4
@spex En pratique, la technique de rejet est plus rapide car elle évite le besoin d'évaluations de la fonction transcendantale.
pjs

2
(suite) rejet: 0,52 s Tous ont donné des moyennes et des écarts types identiques (jusqu'à 3 sig. fig). Comme prévu, l'échantillonnage de rejet a échoué 27% du temps (4 / pi-1), il fallait donc 27% de nombres aléatoires de plus que btilly mais 15% de moins que sigfpe. Cela confirme les commentaires de pjs et d'autres selon lesquels l'échantillonnage par rejet est probablement la meilleure approche, à moins que les aléas soient très coûteux à générer.
Peter Davidson

Réponses:


189

Abordons cela comme l'aurait fait Archimède.

Comment générer un point uniformément dans un triangle ABC, où | AB | = | BC |? Rendons cela plus facile en s'étendant à un parallélogramme ABCD. Il est facile de générer des points uniformément dans ABCD. Nous choisissons uniformément un point aléatoire X sur AB et Y sur BC et choisissons Z tel que XBYZ est un parallélogramme. Pour obtenir un point uniformément choisi dans le triangle d'origine, il suffit de replier tous les points qui apparaissent dans ADC vers ABC le long de AC.

Considérons maintenant un cercle. À la limite, nous pouvons le considérer comme une infinité de triangles isocèles ABC avec B à l'origine et A et C sur la circonférence disparaissant les uns près des autres. Nous pouvons choisir l'un de ces triangles simplement en choisissant un angle thêta. Nous devons donc maintenant générer une distance par rapport au centre en choisissant un point dans le ruban ABC. Encore une fois, étendez-vous à ABCD, où D est maintenant deux fois le rayon du centre du cercle.

Choisir un point aléatoire dans ABCD est facile en utilisant la méthode ci-dessus. Choisissez un point aléatoire sur AB. Choisissez uniformément un point aléatoire sur la Colombie-Britannique. C'est à dire. choisir une paire de nombres aléatoires x et y uniformément sur [0, R] en donnant les distances du centre. Notre triangle est un mince ruban, donc AB et BC sont essentiellement parallèles. Le point Z est donc simplement à une distance x + y de l'origine. Si x + y> R, nous replions vers le bas.

Voici l'algorithme complet pour R = 1. J'espère que vous êtes d'accord, c'est assez simple. Il utilise trig, mais vous pouvez donner une garantie sur la durée et le nombre d' random()appels dont il a besoin, contrairement à l'échantillonnage de rejet.

t = 2*pi*random()
u = random()+random()
r = if u>1 then 2-u else u
[r*cos(t), r*sin(t)]

Le voici dans Mathematica.

f[] := Block[{u, t, r},
  u = Random[] + Random[];
  t = Random[] 2 Pi;
  r = If[u > 1, 2 - u, u];
  {r Cos[t], r Sin[t]}
]

ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]

entrez la description de l'image ici


6
@Karelzarath J'aime la notion contre-intuitive d'un triangle infiniment fin qui est toujours plus large à une extrémité que l'autre :-) Il obtient la bonne réponse.
sigfpe

2
@hammar Pas sûr qu'il se généralise bien à n dimensions. Mais en 3D, vous pouvez utiliser un autre résultat d'Archimède! Utilisez le théorème de la "boîte à chapeau" pour générer un point sur le cylindre (facile!), Puis remettez-le en correspondance avec la sphère. Cela donne une direction. Maintenant, utilisez-le random()+random()+random()avec un pliage plus complexe (c'est-à-dire un pli à 6 voies d'un parallélépipède infinitésimal fin vers un téraèdre). Pas convaincu cependant que c'est une bonne méthode.
sigfpe

2
J'ai pensé 1 min pour comprendre la différence entre random () + random () et 2 * random () ... Je suis tellement stupide: /
JiminP

3
@Tharwen Remarquez comment dans un cercle il y a plus de points au rayon 0,9-1,0 qu'au rayon 0,0-0,1. random () + random () génère des rayons plus susceptibles d'être autour de 1,0 mais se situent dans la plage 0,0-2,0. Une fois repliés, ils sont plus susceptibles d'être autour de 1,0 et toujours dans la plage de 0,0 à 1,0. De plus, c'est exactement la proportion nécessaire dans la première phrase de ce commentaire. Une réduction de moitié produit plus de nombres autour de la marque 0,5 et ce serait faux.
sigfpe

2
@Tharwen Essayez d'utiliser les deux schémas pour générer des nombres aléatoires et voir ce que vous obtenez. 2 * random () donne des nombres uniformément répartis entre 0 et 2. random () + random () vous donne des nombres entre 0 et 2 mais il y aura (généralement) plus de nombres près de 1,0 que de 0,0 ou 2,0. C'est comme si le fait de lancer deux dés et de sommer donne plus de 7 que tout autre nombre.
sigfpe du

134

Comment générer un point aléatoire dans un cercle de rayon R :

r = R * sqrt(random())
theta = random() * 2 * PI

(En supposant random()donne une valeur entre 0 et 1 uniformément)

Si vous souhaitez convertir cela en coordonnées cartésiennes, vous pouvez le faire

x = centerX + r * cos(theta)
y = centerY + r * sin(theta)


Pourquoi sqrt(random())?

Regardons les mathématiques qui mènent à sqrt(random()). Supposons pour plus de simplicité que nous travaillons avec le cercle unitaire, c'est-à-dire R = 1.

La distance moyenne entre les points doit être la même quelle que soit la distance du centre que nous regardons. Cela signifie par exemple, qu'en regardant sur le périmètre d'un cercle de circonférence 2, nous devrions trouver deux fois plus de points que le nombre de points sur le périmètre d'un cercle de circonférence 1.


                

Puisque la circonférence d'un cercle (2π r ) croît linéairement avec r , il s'ensuit que le nombre de points aléatoires devrait croître linéairement avec r . En d'autres termes, la fonction de densité de probabilité souhaitée (PDF) croît linéairement. Puisqu'un PDF doit avoir une aire égale à 1 et le rayon maximum est 1, nous avons


                

Nous savons donc à quoi devrait ressembler la densité souhaitée de nos valeurs aléatoires. Maintenant: comment générer une telle valeur aléatoire alors que tout ce que nous avons est une valeur aléatoire uniforme entre 0 et 1?

Nous utilisons une astuce appelée échantillonnage par transformée inverse

  1. A partir du PDF, créez la fonction de distribution cumulative (CDF)
  2. Miroir ceci le long de y = x
  3. Appliquez la fonction résultante à une valeur uniforme entre 0 et 1.

Cela semble compliqué? Permettez-moi d'insérer un blockquote avec une petite piste latérale qui transmet l'intuition:

Supposons que nous voulons générer un point aléatoire avec la distribution suivante:

                

C'est

  • 1/5 des points uniformément entre 1 et 2, et
  • 4/5 des points uniformément entre 2 et 3.

Le CDF est, comme son nom l'indique, la version cumulative du PDF. Intuitivement: alors que PDF ( x ) décrit le nombre de valeurs aléatoires à x , CDF ( x ) décrit le nombre de valeurs aléatoires inférieures à x .

Dans ce cas, le CDF ressemblerait à:

                

Pour voir comment cela est utile, imaginez que nous tirons des balles de gauche à droite à des hauteurs uniformément réparties. Lorsque les balles atteignent la ligne, elles tombent au sol:

                

Voyez comment la densité des balles au sol correspond à notre distribution souhaitée! Nous y sommes presque!

Le problème est que pour cette fonction, l' axe y est la sortie et l' axe x est l' entrée . Nous ne pouvons que "tirer des balles à partir du sol"! Nous avons besoin de la fonction inverse!

C'est pourquoi nous reflétons le tout; x devient y et y devient x :

                

Nous appelons cela CDF -1 . Pour obtenir des valeurs selon la distribution souhaitée, nous utilisons CDF -1 (random ()).

… Donc, revenons à la génération de valeurs de rayon aléatoires où notre PDF est égal à 2 x .

Étape 1: créer le CDF:

Puisque nous travaillons avec des réels, le CDF est exprimé comme l'intégrale du PDF.

CDF ( x ) = ∫ 2 x = x 2

Étape 2: miroir du CDF le long de y = x :

Mathématiquement, cela se résume à permuter x et y et à résoudre pour y :

CDF :      y = x 2
Swap:    x = y 2
Résoudre:    y = √ x
CDF -1 :   y = √ x

Étape 3: appliquez la fonction résultante à une valeur uniforme entre 0 et 1

CDF -1 (aléatoire ()) = √ aléatoire ()

C'est ce que nous avons décidé de tirer :-)


Cet algorithme peut être utilisé pour générer efficacement des points sur l'anneau.
Ivan Kovtun

Sur le ring? Comme avec un rayon fixe? Je ne sais pas si je comprends votre question, mais si vous avez un rayon fixe, il vous suffit de randomiser l'angle.
aioobe

2
J'ai essayé d'utiliser un mot plus simple "Ring" au lieu de Annulus - région délimitée par deux cercles concentriques. Dans ce cas, l'algorithme de rejet devient inefficace et le premier algorithme supérieur est difficile à généraliser. Et le boîtier d'angle avec un rayon est également couvert avec votre algorithme. Nous générons toujours le rayon en sqrt (aléatoire (min_radius ^ 2, max_radius ^ 2)) même lorsque min_radius == max_radius.
Ivan Kovtun

1
Oh sympa! Pour être clair, quand vous dites random(min_radius², max_radius²), voulez-vous dire quelque chose d'équivalent à random() * (max_radius² - min_radius²) + min_radius², où random()renvoie une valeur uniforme entre 0 et 1?
aioobe

oui, c'est exactement ce que je veux dire: radius = sqrt (random () * (max_radius² - min_radius²) + min_radius²).
Ivan Kovtun

27

Voici une solution simple et rapide.

Choisissez deux nombres aléatoires dans la plage (0, 1), à savoir aet b. Si b < a, échangez-les. Votre point est(b*R*cos(2*pi*a/b), b*R*sin(2*pi*a/b)) .

Vous pouvez penser à cette solution comme suit. Si vous preniez le cercle, le coupiez, puis le redressiez, vous obtiendriez un triangle rectangle. Échelle que vers le bas triangle, et vous auriez un triangle de (0, 0)à (1, 0)à (1, 1)et revenir de nouveau (0, 0). Toutes ces transformations modifient uniformément la densité. Ce que vous avez fait, c'est uniformément choisi un point aléatoire dans le triangle et inversé le processus pour obtenir un point dans le cercle.


Cela, pour une raison quelconque, me donne une distribution beaucoup plus uniforme que la réponse acceptée, bien que j'avais besoin de diviser les coordonnées par le rayon, sinon c'est à l'intérieur d'un cercle de R ^ 2
Greg Zaal

3
Merci, c'est votre code en Java, peut-être que quelqu'un le trouvera utile: float random1 = MathUtils.random (); float random2 = MathUtils.random (); float randomXPoint = random2 * radius MathUtils.cos (MathUtils.PI2 * random1 / random2); float randomYPoint = random2 * radius MathUtils.sin (MathUtils.PI2 * random1 / random2);
Tony Ceralva

très bon! J'aime l'idée d'une plus grande probabilité de centraliser les points, donc si nous n'échangeons pas quand b < anous pouvons y arriver! par exemple en javascript jsfiddle.net/b0sb5ogL/1
Guilherme

Je pense que votre solution est mauvaise. Cela ne donne pas de résultats uniformes. Vérifiez cette capture d'écran prntscr.com/fizxgc
bolec_kolec

4
Pouvez-vous expliquer un peu plus comment couper le cercle et le redresser?
kec

21

Notez la densité de point proportionnelle à l' inverse du carré du rayon, donc au lieu de choisir à rpartir [0, r_max], choisir à partir [0, r_max^2], puis calculer vos coordonnées comme:

x = sqrt(r) * cos(angle)
y = sqrt(r) * sin(angle)

Cela vous donnera une distribution uniforme des points sur un disque.

http://mathworld.wolfram.com/DiskPointPicking.html


12

Pensez-y de cette façon. Si vous avez un rectangle où un axe est un rayon et un est un angle, et vous prenez les points à l'intérieur de ce rectangle qui sont proches du rayon 0. Ceux-ci tomberont tous très près de l'origine (c'est-à-dire rapprochés sur le cercle). Cependant, les points proches du rayon R, ceux-ci tomberont tous près du bord du cercle (c'est-à-dire éloignés les uns des autres).

Cela pourrait vous donner une idée de la raison pour laquelle vous obtenez ce comportement.

Le facteur dérivé sur ce lien vous indique la quantité de zone correspondante dans le rectangle qui doit être ajustée pour ne pas dépendre du rayon une fois qu'il est mappé au cercle.

Edit: Donc, ce qu'il écrit dans le lien que vous partagez est: "C'est assez facile à faire en calculant l'inverse de la distribution cumulative, et nous obtenons pour r:".

La prémisse de base est ici que vous pouvez créer une variable avec une distribution souhaitée à partir d'un uniforme en mappant l'uniforme par la fonction inverse de la fonction de distribution cumulative de la fonction de densité de probabilité souhaitée. Pourquoi? Prenez-le pour acquis pour l'instant, mais c'est un fait.

Voici mon explication intuitive des mathématiques. La fonction de densité f (r) par rapport à r doit être proportionnelle à r lui-même. Comprendre ce fait fait partie de tous les livres de calcul de base. Voir les sections sur les éléments de la zone polaire. Quelques autres affiches l'ont mentionné.

Nous l'appellerons donc f (r) = C * r;

Cela s'avère être la majeure partie du travail. Maintenant, puisque f (r) devrait être une densité de probabilité, vous pouvez facilement voir qu'en intégrant f (r) sur l'intervalle (0, R) vous obtenez que C = 2 / R ^ 2 (c'est un exercice pour le lecteur .)

Ainsi, f (r) = 2 * r / R ^ 2

OK, c'est ainsi que vous obtenez la formule dans le lien.

Ensuite, la dernière partie part de la variable aléatoire uniforme u dans (0,1) que vous devez mapper par la fonction inverse de la fonction de distribution cumulative à partir de cette densité souhaitée f (r). Pour comprendre pourquoi c'est le cas, vous devez probablement trouver un texte de probabilité avancé comme Papoulis (ou le dériver vous-même.)

En intégrant f (r) vous obtenez F (r) = r ^ 2 / R ^ 2

Pour trouver la fonction inverse de cela, vous définissez u = r ^ 2 / R ^ 2, puis résolvez pour r, ce qui vous donne r = R * sqrt (u)

Cela a également un sens intuitif, u = 0 doit correspondre à r = 0. De plus, u = 1 doit correspondre à r = R. De plus, il passe par la fonction racine carrée, qui a du sens et correspond au lien.


10

La raison pour laquelle la solution naïve ne fonctionne pas est qu'elle donne une densité de probabilité plus élevée aux points les plus proches du centre du cercle. En d'autres termes, le cercle qui a un rayon r / 2 a une probabilité r / 2 d'obtenir un point sélectionné, mais il a une aire (nombre de points) pi * r ^ 2/4.

Par conséquent, nous voulons qu'une densité de probabilité de rayon ait la propriété suivante:

La probabilité de choisir un rayon plus petit ou égal à un r donné doit être proportionnelle à l'aire du cercle de rayon r. (parce que nous voulons avoir une distribution uniforme sur les points et des zones plus grandes signifient plus de points)

En d'autres termes, nous voulons que la probabilité de choisir un rayon entre [0, r] soit égale à sa part de l'aire globale du cercle. L'aire totale du cercle est pi * R ^ 2, et l'aire du cercle de rayon r est pi * r ^ 2. Ainsi, nous aimerions que la probabilité de choisir un rayon entre [0, r] soit (pi * r ^ 2) / (pi * R ^ 2) = r ^ 2 / R ^ 2.

Vient maintenant le calcul:

La probabilité de choisir un rayon entre [0, r] est l'intégrale de p (r) dr de 0 à r (c'est simplement parce que nous ajoutons toutes les probabilités des rayons les plus petits). Nous voulons donc l'intégrale (p (r) dr) = r ^ 2 / R ^ 2. Nous pouvons clairement voir que R ^ 2 est une constante, donc tout ce que nous devons faire est de déterminer quel p (r), une fois intégré, nous donnerait quelque chose comme r ^ 2. La réponse est clairement r * constante. intégrale (r * constante dr) = r ^ 2/2 * constante. Cela doit être égal à r ^ 2 / R ^ 2, donc constant = 2 / R ^ 2. Vous avez donc la distribution de probabilité p (r) = r * 2 / R ^ 2

Remarque: Une autre façon plus intuitive de penser au problème est d'imaginer que vous essayez de donner à chaque cercle de rayon une densité de probabilité égale à la proportion du nombre de points qu'il a sur sa circonférence. Ainsi un cercle qui a un rayon r aura 2 "pi" r "points" sur sa circonférence. Le nombre total de points est pi * R ^ 2. Ainsi, vous devriez donner la probabilité du cercle ra égale à (2 * pi * r) / (pi * R ^ 2) = 2 * r / R ^ 2. C'est beaucoup plus facile à comprendre et plus intuitif, mais ce n'est pas aussi sain mathématiquement.


9

Soit ρ (rayon) et φ (azimut) deux variables aléatoires correspondant aux coordonnées polaires d'un point arbitraire à l'intérieur du cercle. Si les points sont uniformément distribués, alors quelle est la fonction de répartition de ρ et φ?

Pour tout r: 0 <r <R, la probabilité que la coordonnée de rayon ρ soit inférieure à r est

P [ρ <r] = P [le point est dans un cercle de rayon r] = S1 / S0 = (r / R) 2

Où S1 et S0 sont les zones de cercle de rayon r et R respectivement. Ainsi, le CDF peut être donné comme:

          0          if r<=0
  CDF =   (r/R)**2   if 0 < r <= R
          1          if r > R

Et PDF:

PDF = d/dr(CDF) = 2 * (r/R**2) (0 < r <= R).

Notez que pour R = 1 variable aléatoire sqrt (X) où X est uniforme sur [0, 1) a ce CDF exact (car P [sqrt (X) <y] = P [x <y ** 2] = y * * 2 pour 0 <y <= 1).

La distribution de φ est évidemment uniforme de 0 à 2 * π. Vous pouvez maintenant créer des coordonnées polaires aléatoires et les convertir en cartésiennes à l'aide d'équations trigonométriques:

x = ρ * cos(φ)
y = ρ * sin(φ)

Je ne peux pas résister à publier du code python pour R = 1.

from matplotlib import pyplot as plt
import numpy as np

rho = np.sqrt(np.random.uniform(0, 1, 5000))
phi = np.random.uniform(0, 2*np.pi, 5000)

x = rho * np.cos(phi)
y = rho * np.sin(phi)

plt.scatter(x, y, s = 4)

Tu auras

entrez la description de l'image ici


7

Cela dépend vraiment de ce que vous entendez par «uniformément aléatoire». C'est un point subtil et vous pouvez en savoir plus sur la page wiki ici: http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29 , où le même problème, donnant des interprétations différentes de `` uniformément aléatoire '' donne réponses différentes!

Selon la façon dont vous choisissez les points, la distribution peut varier, même s'ils sont uniformément aléatoires certains sens.

Il semble que l'entrée de blog tente de le rendre uniformément aléatoire dans le sens suivant: si vous prenez un sous-cercle du cercle, avec le même centre, la probabilité que le point tombe dans cette région est proportionnelle à la zone de la région. Cela, je crois, tente de suivre l'interprétation désormais standard de `` uniformément aléatoire '' pour les régions 2D avec des zones définies sur elles : la probabilité qu'un point tombe dans une région (avec une zone bien définie) est proportionnelle à la zone de cette région.


5
Ou plutôt, la probabilité que le point tombe dans n'importe quelle région arbitraire est proportionnelle à la zone de la région - en supposant que la région a une zone .
ShreevatsaR

@Shree: Correct, c'est ce que je voulais dire par ma déclaration entre parenthèses. Je vais être plus clair, merci. btw, à propos du blog, il n'y avait aucune preuve réelle que les zones arbitraires donnent des probabilités proportionnelles, c'est pourquoi j'ai choisi de l'exprimer ainsi.

6

Voici mon code Python pour générer numdes points aléatoires à partir d'un cercle de rayon rad:

import matplotlib.pyplot as plt
import numpy as np
rad = 10
num = 1000

t = np.random.uniform(0.0, 2.0*np.pi, num)
r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
x = r * np.cos(t)
y = r * np.sin(t)

plt.plot(x, y, "ro", ms=1)
plt.axis([-15, 15, -15, 15])
plt.show()

1
Pourquoi pas juste r = np.sqrt(np.random.uniform(0.0, rad**2, num))?

4

Je pense que dans ce cas, l'utilisation de coordonnées polaires est un moyen de compliquer le problème, il serait beaucoup plus facile si vous choisissez des points aléatoires dans un carré avec des côtés de longueur 2R, puis sélectionnez les points (x,y)tels que x^2+y^2<=R^2.


Vous voulez dire x ^ 2 + y ^ 2 <= R ^ 2 je pense.
sigfpe

1
Il s'agit d'un échantillonnage de rejet. Ce n'est pas grave, mais cela signifie que le temps de calcul varie quelque peu, ce qui pourrait être un problème.
Steve Bennett

Tous les carrés sont à 4 côtés.
xaxxon

Cet algorithme est plus efficace que tout ce qui implique des racines carrées ou des calculs sin / cos. Il rejette moins de 21,5% des points du carré.
Ivan Kovtun

3

Solution en Java et l'exemple de distribution (2000 points)

public void getRandomPointInCircle() {
    double t = 2 * Math.PI * Math.random();
    double r = Math.sqrt(Math.random());
    double x = r * Math.cos(t);
    double y = r * Math.sin(t);
    System.out.println(x);
    System.out.println(y);
}

Distribution 2000 points

basé sur la solution previus https://stackoverflow.com/a/5838055/5224246 de @sigfpe


2

D'abord, nous générons un cdf [x] qui est

Probabilité qu'un point soit inférieur à la distance x du centre du cercle. Supposons que le cercle ait un rayon de R.

évidemment si x est nul alors cdf [0] = 0

évidemment si x est R alors le cdf [R] = 1

évidemment si x = r alors le cdf [r] = (Pi r ^ 2) / (Pi R ^ 2)

En effet, chaque "petite zone" sur le cercle a la même probabilité d'être sélectionnée, donc la probabilité est proportionnelle à la zone en question. Et l'aire à une distance x du centre du cercle est Pi r ^ 2

donc cdf [x] = x ^ 2 / R ^ 2 parce que les Pi s'annulent

nous avons cdf [x] = x ^ 2 / R ^ 2 où x va de 0 à R

Nous résolvons donc pour x

R^2 cdf[x] = x^2

x = R Sqrt[ cdf[x] ]

Nous pouvons maintenant remplacer cdf par un nombre aléatoire de 0 à 1

x = R Sqrt[ RandomReal[{0,1}] ]

finalement

r = R Sqrt[  RandomReal[{0,1}] ];
theta = 360 deg * RandomReal[{0,1}];
{r,theta}

on obtient les coordonnées polaires {0,601168 R, 311,915 deg}


1

Il existe une relation linéaire entre le rayon et le nombre de points "près" de ce rayon, il doit donc utiliser une distribution de rayon qui rend également le nombre de points de données près d'un rayon rproportionnel à r.


1

J'ai utilisé une fois cette méthode: celle-ci peut être totalement non optimisée (c'est-à-dire qu'elle utilise un tableau de points donc son inutilisable pour les grands cercles) mais donne une distribution aléatoire suffisante. Vous pouvez ignorer la création de la matrice et dessiner directement si vous le souhaitez. La méthode consiste à randomiser tous les points d'un rectangle qui se trouvent à l'intérieur du cercle.

bool[,] getMatrix(System.Drawing.Rectangle r) {
    bool[,] matrix = new bool[r.Width, r.Height];
    return matrix;
}

void fillMatrix(ref bool[,] matrix, Vector center) {
    double radius = center.X;
    Random r = new Random();
    for (int y = 0; y < matrix.GetLength(0); y++) {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            double distance = (center - new Vector(x, y)).Length;
            if (distance < radius) {
                matrix[x, y] = r.NextDouble() > 0.5;
            }
        }
    }

}

private void drawMatrix(Vector centerPoint, double radius, bool[,] matrix) {
    var g = this.CreateGraphics();

    Bitmap pixel = new Bitmap(1,1);
    pixel.SetPixel(0, 0, Color.Black);

    for (int y = 0; y < matrix.GetLength(0); y++)
    {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            if (matrix[x, y]) {
                g.DrawImage(pixel, new PointF((float)(centerPoint.X - radius + x), (float)(centerPoint.Y - radius + y)));
            }
        }
    }

    g.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
    System.Drawing.Rectangle r = new System.Drawing.Rectangle(100,100,200,200);
    double radius = r.Width / 2;
    Vector center = new Vector(r.Left + radius, r.Top + radius);
    Vector normalizedCenter = new Vector(radius, radius);
    bool[,] matrix = getMatrix(r);
    fillMatrix(ref matrix, normalizedCenter);
    drawMatrix(center, radius, matrix);
}

entrez la description de l'image ici


3
Les distributions ne sont pas "assez aléatoires". Ils sont aléatoires ou non pour une définition donnée du hasard. Votre réponse est oblique: vous ne commentez pas votre code et n'expliquez pas comment vous y arrivez. Les réponses obliques sont difficiles à suivre et plus difficiles à faire confiance.
Richard

1

L'élément d'aire dans un cercle est dA = rdr * dphi. Ce facteur supplémentaire r a détruit votre idée de choisir au hasard ar et phi. Alors que phi est distribué à plat, r ne l'est pas, mais à plat dans 1 / r (c'est-à-dire que vous êtes plus susceptible de toucher la frontière que "l'oeil de boeuf").

Donc, pour générer des points uniformément répartis sur le cercle, choisissez phi à partir d'une distribution plate et r à partir d'une distribution 1 / r.

Vous pouvez également utiliser la méthode Monte Carlo proposée par Mehrdad.

ÉDITER

Pour choisir un r aléatoire aléatoire dans 1 / r, vous pouvez choisir un x aléatoire dans l'intervalle [1 / R, infini] et calculer r = 1 / x. r est alors réparti à plat dans 1 / r.

Pour calculer un phi aléatoire, choisissez un x aléatoire dans l'intervalle [0, 1] et calculez phi = 2 * pi * x.


Comment choisir exactement un r dans "une distribution 1 / r" ?
aioobe

0

Je ne sais pas si cette question est toujours ouverte pour une nouvelle solution avec toutes les réponses déjà données, mais il se trouve que j'ai été confronté exactement à la même question moi-même. J'ai essayé de "raisonner" avec moi-même pour une solution, et j'en ai trouvé une. Ce pourrait être la même chose que certains l'ont déjà suggéré ici, mais de toute façon ici c'est:

pour que deux éléments de la surface du cercle soient égaux, en supposant des dr égaux, nous devons avoir dtheta1 / dtheta2 = r2 / r1. Écriture de l'expression de la probabilité pour cet élément comme P (r, thêta) = P {r1 <r <r1 + dr, thêta1 <thêta <thêta + dthêta1} = f (r, thêta) * dr * dthêta1, et définition des deux probabilités (pour r1 et r2) égales, on arrive à (en supposant que r et thêta sont indépendants) f (r1) / r1 = f (r2) / r2 = constant, ce qui donne f (r) = c * r. Et le reste, la détermination de la constante c découle de la condition sur f (r) étant un PDF.


Approche intéressante pour commencer avec dtheta1 / dtheta2 = r2 / r1. Pourriez-vous expliquer comment vous avez trouvé cette équation?
aioobe

Comme d'autres l'ont mentionné (honk, par exemple), un élément différentiel de la surface d'un cercle est donné comme r dr dtheta, donc si nous supposons r1 = r2, alors nous aurons dr1 * dtheta1 = dr2 * dtheta2 et le reste suit .
arsaKasra

0

Une solution de programmation:

  • Créez un bitmap (une matrice de valeurs booléennes). Il peut être aussi grand que vous le souhaitez.
  • Tracez un cercle dans cette carte binaire.
  • Créez une table de correspondance des points du cercle.
  • Choisissez un index aléatoire dans cette table de recherche.
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

bool matrix[MATRIX_SIZE][MATRIX_SIZE] = {0};

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        matrix[x][y] = true;

        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;

      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

Le bitmap n'est nécessaire que pour l'explication de la logique. Voici le code sans le bitmap:

const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;
      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

0

Je ne suis toujours pas sûr de l'exact '(2 / R2) × r' mais ce qui est évident, c'est le nombre de points à distribuer dans l'unité donnée 'dr', c'est-à-dire que l'augmentation de r sera proportionnelle à r2 et non à r.

vérifiez de cette façon ... le nombre de points sous un certain angle thêta et entre r (0,1r à 0,2r), c'est-à-dire la fraction du r et le nombre de points entre r (0,6r à 0,7r) serait égal si vous utilisez la génération standard, car la différence n'est que de 0,1r entre deux intervalles. mais comme la zone couverte entre les points (0,6r à 0,7r) sera beaucoup plus grande que la zone couverte entre 0,1r à 0,2r, le nombre égal de points sera légèrement espacé dans une zone plus grande, je suppose que vous le savez déjà, donc la fonction pour générer les points aléatoires ne doit pas être linéaire mais quadratique, (puisque le nombre de points à distribuer dans une unité donnée 'dr', c'est-à-dire l'augmentation de r sera proportionnelle à r2 et non r), donc dans ce cas, il sera inverse de quadratique, puisque le delta que nous avons (0.


Vous êtes le premier à faire référence au théorème de Pythagore ici. Je serais ravi si vous pouviez développer cela avec un chiffre ou deux, à l'appui de votre explication. J'ai du mal à suivre en l'état actuel :-(
aioobe

@aioobe J'ai essayé de reformuler la réponse, je peux ajouter des diagrammes si vous en avez besoin :)
cheesefest

Je comprends pourquoi je ne peux pas l'étaler linéairement. Ce que je ne comprends pas ici, c'est la connexion à Pythagore ou au péché / cos. Peut-être que les diagrammes pourraient m'aider ici.
aioobe

Pythagore est mon erreur, veuillez l'oublier, mais j'espère que vous avez compris la nature quadratique de la fonction, l'exact (2 / R2) × r a besoin d'une preuve et je suis incapable de trouver une preuve pour cela
cheesefest

0

Un tel problème amusant.
La justification de la probabilité qu'un point soit choisi baissant à mesure que la distance par rapport à l'origine de l'axe augmente est expliquée plusieurs fois ci-dessus. Nous tenons compte de cela en prenant la racine de U [0,1]. Voici une solution générale pour un r positif dans Python 3.

import numpy
import math
import matplotlib.pyplot as plt

def sq_point_in_circle(r):
    """
    Generate a random point in an r radius circle 
    centered around the start of the axis
    """

    t = 2*math.pi*numpy.random.uniform()
    R = (numpy.random.uniform(0,1) ** 0.5) * r

    return(R*math.cos(t), R*math.sin(t))

R = 200 # Radius
N = 1000 # Samples

points = numpy.array([sq_point_in_circle(R) for i in range(N)])
plt.scatter(points[:, 0], points[:,1])

entrez la description de l'image ici


0

Vous pouvez également utiliser votre intuition.

L'aire d'un cercle est pi*r^2

Pour r=1

Cela nous donne une superficie de pi. Supposons que nous avons une sorte de fonction fqui perturberait uniformémentN=10 points à l'intérieur d'un cercle. Le rapport ici est10 / pi

Maintenant, nous doublons la surface et le nombre de points

Pour r=2 etN=20

Cela donne une zone de 4piet le rapport est maintenant 20/4piou 10/2pi. Le rapport deviendra de plus en plus petit plus le rayon est grand, car sa croissance est quadratique etN échelles linéaires.

Pour résoudre ce problème, nous pouvons simplement dire

x = r^2
sqrt(x) = r

Si vous générez un vecteur en coordonnées polaires comme celui-ci

length = random_0_1();
angle = random_0_2pi();

Plus de points atterriraient autour du centre.

length = sqrt(random_0_1());
angle = random_0_2pi();

length n'est plus uniformément distribué, mais le vecteur sera désormais uniformément distribué.


-1

1) Choisissez un X aléatoire entre -1 et 1.

var X:Number = Math.random() * 2 - 1;

2) En utilisant la formule du cercle, calculez les valeurs maximales et minimales de Y étant donné que X et un rayon de 1:

var YMin:Number = -Math.sqrt(1 - X * X);
var YMax:Number = Math.sqrt(1 - X * X);

3) Choisissez un Y aléatoire entre ces extrêmes:

var Y:Number = Math.random() * (YMax - YMin) + YMin;

4) Incorporez vos valeurs d'emplacement et de rayon dans la valeur finale:

var finalX:Number = X * radius + pos.x;
var finalY:Number = Y * radois + pos.y;

2
Pas uniforme - la probabilité pour [-1, 0] est beaucoup plus élevée que pour [0, 0], étant donné que p ([- 1, Y]) = p ([0, Y]), et qu'il n'y a qu'un seul choix pour [-1, Y] et plusieurs choix pour [0, Y].
Amadan

Cette solution favorise les points vers les côtés gauche et droit du cercle. Les points avec x proche de zéro sont sous-représentés. Pas du tout une distribution uniforme.
Dawood ibn Kareem
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.