Marche aléatoire 🍷#
Le mouvement brownien, aussi appelé marche aléatoire, revêt une importance particulière dans l’étude de la nature. Il a permis à l’époque de confirmer l’existence des atomes, ainsi que d’évaluer le nombre d’Avogadro. Les recherches associées à ce mouvement sont encore utilisées aujourd’hui dans de nombreux domaines des sciences physiques, mais aussi en finance (notamment pour l’analyse des cours boursiers). On parle alors de processus stochastique. Ces travaux sont associés à des scientifiques prestigieux tels qu’Albert Einstein et Jean Perrin. On se propose dans ce petit papier de modéliser le mouvement brownien suivant une approche élémentaire. On se servira du modèle de l’ivrogne (représentant une particule).[3]

Robert Brown#

Robert Brown (1773-1858) était un botaniste écossais célèbre pour sa découverte du mouvement Brownien en 1827. Ce phénomène se réfère à l’agitation aléatoire des particules microscopiques en suspension dans un fluide, qu’il observa en examinant des grains de pollen dans l’eau. Brown croyait initialement que ce mouvement était une caractéristique des particules vivantes, mais il s’est vite rendu compte qu’il se produisait même avec des particules inanimées. Le mouvement Brownien a été fondamental dans le développement de la physique statistique, particulièrement dans les travaux d’Albert Einstein au début du 20e siècle, qui a expliqué ce mouvement par les collisions entre les particules et les molécules de fluide.[1]
Jean Perrin#

Jean Perrin (1870-1942) était un physicien français Lillois qui a joué un rôle crucial dans la validation expérimentale du mouvement brownien. En 1908, il a confirmé les travaux théoriques d’Albert Einstein sur ce phénomène en étudiant la répartition des particules en suspension dans un liquide. Perrin a démontré que ce mouvement aléatoire des particules était causé par les collisions avec les molécules du liquide, fournissant ainsi une preuve directe de l’existence des atomes et des molécules. Ses travaux ont été essentiels pour établir la théorie atomique, et en 1926, il a reçu le prix Nobel de physique pour ses contributions à la physique moléculaire et atomique.[2]
Présentation du problème#

Prudence
L’objectif est de présenter un code simple et compréhensible. Il ne s’agit pas d’optimiser excessivement le code Python 🐍, ni de tirer parti des multiples cœurs des processeurs modernes, et encore moins d’utiliser des bibliothèques comme CUDA, qui permettent le calcul massivement parallèle sur un GPU. Une optimisation sommaire est proposée en annexe.
Dans l’étude du transport de grandeurs physiques par des molécules, le physicien peut, en première approximation, adopter un modèle stochastique appelé marche aléatoire. C’est le cas, par exemple, pour l’interprétation de la viscosité, qui peut être considérée comme le transport d’une quantité de mouvement. Comme mentionné plus haut, le modèle utilisé est celui de l’ivrogne, où celui-ci effectue aléatoirement un pas d’une longueur fixe, notée
Code 1
- représentation simple du mouvement de l’ivrogne#
# Importation des bibliothèques nécessaires
import random # Pour générer des valeurs aléatoires
import matplotlib # Pour configurer les paramètres globaux de matplotlib
import matplotlib.pyplot as plt # Pour créer des graphiques
# Configuration globale de la résolution des graphiques
matplotlib.rcParams['figure.dpi'] = 150 # Définit la résolution des images/vidéos pour une meilleure qualité visuelle
# Paramètres
NBR_PAS = 100 # Nombre de pas que fera l'ivrogne dans sa marche aléatoire
trajectoire = [] # Liste pour stocker les positions à chaque pas
# Génération de la trajectoire avec marche aléatoire (modèle de l'ivrogne)
position = 0 # Initialisation de la position à 0
for i in range(NBR_PAS):
pas = random.choice([-1, 1]) # L'ivrogne fait un pas de +1m ou -1m (choix aléatoire)
trajectoire.append(pas) # Ajoute le pas à la liste
# Affichage du graphique
plt.plot(trajectoire, ".:", linewidth=0.7, markersize=5, color="black", markeredgecolor="red") # Tracé de la courbe
plt.title("Représentation du mouvement de l'ivrogne",fontsize=15) # Titre du graphique
plt.xlabel('Numéro du pas', fontsize=14) # Étiquette pour l'axe des x (le numéro du pas)
plt.ylabel('Position (m)', fontsize=14) # Étiquette pour l'axe des y (la position en mètres)
plt.yticks(range(min(trajectoire), max(trajectoire) + 1)) # Ajuste les graduations sur l'axe y pour montrer toutes les positions possibles
plt.figtext(0.70, 0.015, 'Rémi MEVAERE - sciences-physiques.net', fontsize=6, color='black', alpha=0.9, fontweight='normal') # Ajout d'une mention en bas à droite
# Afficher ou sauvegarder l'image
plt.show() # Affiche le graphique à l'écran

Code 2
: Simulation de la trajectoire de 20 ivrognes parcourant 1000 pas#
# Mathématiques et calculs
import random
# Graphiques
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import animation
# Configuration des paramètres de Matplotlib pour les graphiques
matplotlib.rcParams['animation.html'] = 'html5' # Configuration pour affichage des animations
matplotlib.rcParams['figure.dpi'] = 150 # Définition de la résolution des images
# Constantes
NBR_PAS = 1000 # Nombre de pas par ivrogne
NBR_IVROGNE = 20 # Nombre d'ivrognes simulés
trajectoires_ivrognes = [] # Liste pour stocker les trajectoires de chaque ivrogne
X_MAX = 0 # Variable pour suivre la position maximale
X_MIN = 0 # Variable pour suivre la position minimale
# Simulation des trajectoires des ivrognes
for b in range(NBR_IVROGNE):
pas = [] # Liste pour stocker les pas individuels
trajectoire = [] # Liste pour stocker la trajectoire cumulée
# Simulation des pas pour un ivrogne for i in range(NBR_PAS):
pas.append(random.choice([-1, 1])) # Choix aléatoire d'un pas (-1 ou 1)
trajectoire.append(sum(pas)) # Mise à jour de la trajectoire
# Enregistrer la trajectoire de cet ivrogne trajectoires_ivrognes.append(trajectoire)
# Mettre à jour les bornes pour l'axe des ordonnées
MAX_TRAJ = max(trajectoire)
MIN_TRAJ = min(trajectoire)
if MAX_TRAJ > X_MAX:
X_MAX = MAX_TRAJ
if MIN_TRAJ < X_MIN:
X_MIN = MIN_TRAJ
# Création d'une liste des numéros de pas pour l'axe des abscisses
num_pas = [i for i in range(NBR_PAS)]
# Création de la figure et de l'axe pour le graphique
fig, ax = plt.subplots()
ax = plt.axis([0, NBR_PAS, X_MIN-2, X_MAX+2]) # Définition des limites de l'axe
# Création des objets "courbe" pour chaque ivrogne
courbe = []
for c in range(NBR_IVROGNE):
courbe.append(plt.plot([0], [0], '-', linewidth=1, solid_joinstyle='round', label="Ivrogne n°" + str(c))) # Initialiser les courbes
# Embellissement du graphique
plt.title("Trajectoire des ivrognes", fontsize=15)
plt.xlabel('Numéro du pas', fontsize=14)
plt.ylabel("Position (m)", fontsize=14)
plt.figtext(0.70, 0.015, 'Rémi MEVAERE - sciences-physiques.net', fontsize=6, color='black', alpha=0.9, fontweight='normal') # Ajout d'une mention en bas à droite
# Fonction d'animation appelée pour chaque frame
def animate(i):
# Mettre à jour les données pour chaque ivrogne
for b in range(NBR_IVROGNE):
courbe[b][0].set_data(num_pas[0:i], trajectoires_ivrognes[b][0:i]) # Mettre à jour les points tracés
# Création d'une animation, en créant un graphique image par image
myAnimation = animation.FuncAnimation(fig, animate, frames=NBR_PAS, interval=20, repeat=False)
# Sauvegarde de l'animation dans un fichier .mp4 (optionnel)
myAnimation.save("trajectoire_ivrognes.mp4", writer="ffmpeg")
# Affichage du graphique animé
plt.show()
Problématique#
Quelle est la probabilité que l’ivrogne effectue, au total, un déplacement de
Résolution#
Épreuve de Bernoulli#
Nous nous plaçons, comme il est fréquent en physique, dans un cas simplifié. Nous considérons une marche aléatoire unidimensionnelle, décrite le long d’un unique axe
Sur le plan mathématique, nous nous appuierons sur des concepts de probabilité. Chaque déplacement de l’ivrogne correspond à une épreuve, et l’expérience consiste en une succession de
Événement +
: la particule se déplace dans la direction des positifs ;Événement -
: la particule se déplace dans la direction des négatifs.
Relions
Remarque 🧠
Nous pourrions suivre le même raisonnement en paramétrant les déplacements vers la gauche plutôt que ceux vers la droite ; les résultats finaux seraient identiques. En effet, dans notre modèle, l’ivrogne n’a pas de raison particulière de privilégier un déplacement vers la gauche par rapport à un pas vers la droite (les directions sont équiprobables,
On peut ensuite se demander quelle est la probabilité d’obtenir
Notation 🖍️
Avec le théorème central limite#
Pour calculer la probabilité que l’ivrogne se retrouve en position
Pourquoi utiliser le théorème central limite ?
Le théorème central limite est fondamental en probabilité et en statistique, il nous permet d’approcher la distribution binomiale par une loi normale (gaussienne), ce qui simplifie les calculs. Il affirme que la somme de variables aléatoires indépendantes et identiquement distribuées tend vers une distribution normale lorsque le nombre de variables augmente.
Pertinence :
Chaque déplacement élémentaire de l’ivrogne est une variable aléatoire indépendante ;
Les déplacements sont identiquement distribués (chaque pas a la même probabilité d’être à gauche ou à droite) ;
Intérêt :
Simplicité de calcul : Au lieu de manipuler des distributions binomiales complexes pour de grandes valeurs de
, on utilise une gaussienne, beaucoup plus facile à gérer analytiquement ;Prévision des comportements : Il permet de prédire la probabilité de trouver l’ivrogne à une certaine distance de son point de départ après un grand nombre de pas.
Universalité : Ce théorème est applicable à de nombreux systèmes physiques où des variables aléatoires indépendantes s’additionnent, comme en physique statistique, en thermodynamique ou en finance.
Variable aléatoire : déplacement élémentaire#
Définissons une variable aléatoire nommée déplacement élémentaire notée
si l’ivrogne se déplace vers la droite. si l’ivrogne se déplace vers la gauche.
La variable aléatoire
Espérance#
Le résultat étant trivial vu que les deux évènements sont équiprobables.
Variance#
Ecart-type#
Application du Théorème#
Le théorème central limite stipule que pour
En remplaçant
Étant donné que le déplacement net
Code 3
- Vérification de la distribution normale#
Note
Pour la simulation on se facilite la tâche en utilisant un déplacement
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import animation
# Constantes
NBR_PAS = 100 # Nombre de pas pour chaque ivrogne
NBR_IVROGNES = 900000 # Nombre total d'ivrognes simulés
# Configuration des paramètres de Matplotlib pour les graphiques
matplotlib.rcParams['animation.html'] = 'html5' # Configuration pour affichage des animations
matplotlib.rcParams['figure.dpi'] = 150 # Définition de la résolution des images
# Simulation des positions finales des ivrognes
deplacements = np.random.choice([-1, 1], size=(NBR_IVROGNES, NBR_PAS))
positions_finales = np.sum(deplacements, axis=1)
# Détermination des positions minimale et maximale pour ajuster les limites du graphique
MIN, MAX = positions_finales.min(), positions_finales.max()
# Préparation de la figure pour l'animation
fig, ax = plt.subplots()
ax.set_xlim(MIN - 5, MAX + 5)
plt.xlabel('Position finale', fontsize=12)
plt.ylabel("Probabilité", fontsize=12)
plt.title('Distribution des positions finales des ivrognes')
plt.figtext(0.70, 0.015, 'sciences-physiques.net', fontsize=6, color='black', alpha=0.9,
fontweight='normal')
# Initialisation de l'histogramme
nombre_bandes = MAX - MIN + 1
# Calcul de la courbe gaussienne théorique
x_gauss = np.linspace(MIN, MAX, 1000)
P_gauss = (1 / np.sqrt(2 * np.pi * NBR_PAS)) * np.exp(-x_gauss ** 2 / (2 * NBR_PAS))
# Fonction d'animation pour mettre à jour l'histogramme
def animer_histogramme(i):
plt.cla() # Efface le contenu précédent de la figure
donnees_histogramme = positions_finales[0:i] # Sélectionne les positions jusqu'à l'ivrogne i
# Tracer l'histogramme normalisé (probabilités) comptes, bandes, patches = plt.hist(donnees_histogramme, bins=nombre_bandes, range=(MIN - 0.5, MAX + 0.5),
density=True, facecolor='blue', alpha=0.5, edgecolor='black')
# Calcul de la largeur des bandes
largeur_bande = bandes[1] - bandes[0]
# Tracer la courbe théorique gaussienne ajustée à la largeur des bandes
plt.plot(x_gauss, P_gauss * largeur_bande * 2, color='red', lw=2, label='Gaussienne théorique')
# Mise à jour des paramètres de la figure
plt.title(f"Distribution des positions finales : {i} ivrogne(s)", fontsize=15)
plt.xlabel('Position finale', fontsize=14)
plt.ylabel("Probabilité", fontsize=14)
plt.xlim(MIN - 5, MAX + 5)
plt.ylim(0, max(comptes.max(), (P_gauss * largeur_bande).max()) * 1.1) # Ajustement dynamique des ordonnées
# Création de la liste des frames pour l'animation
liste_frames = (
list(range(1, 11)) +
[i * 10 for i in range(2, 11)] +
[i * 100 for i in range(2, 11)] +
[i * 1000 for i in range(2, 11)] +
[i * 10000 for i in range(2, NBR_IVROGNES // 10000 + 1)]
)
# Ajustement des marges pour laisser de l'espace autour des axes
plt.subplots_adjust(left=0.15, right=0.95, top=0.9, bottom=0.1)
# Création de l'animation en utilisant la fonction animer_histogramme
mon_animation = animation.FuncAnimation(fig, animer_histogramme, frames=liste_frames, interval=200, repeat=False)
# Optionnel : sauvegarde de l'animation dans un fichier vidéo
mon_animation.save("distribution_ivrognes.mp4", writer="ffmpeg")
# Affichage de l'animation
plt.show()
Probabilité de parcourir une distance #
Revenons à l’ivrogne. Nous cherchons à connaître la distance
De plus, la durée totale est donnée par (
En utilisant ces relations, on peut exprimer la probabilité de trouver l’ivrogne à une distance
Sachant que
Distance quadratique moyenne parcourue#
Nous souhaitons calculer la valeur moyenne de
Mais étant donné que
Ainsi, la distance quadratique moyenne parcourue est (
Interprétation physique#
La distribution s’élargit proportionnellement à la racine carrée de la durée
Code 4
- Accord avec la théorie#
Optimization 🔩
Sur mon ordinateur, ce code absolument pas optimisé prend une durée très longue (plus de 16 minutes). Les versions Vectorisée et CUDA disponibles en Annexes sont beaucoup plus rapides (40 secondes et 3 secondes).
import random
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# Configuration des paramètres de Matplotlib pour les graphiques
matplotlib.rcParams['figure.dpi'] = 150 # Résolution des images
# Constantes
NBR_IVROGNES = 2000 # Nombre d'ivrognes simulés
liste_NBR_PAS = (
list(range(10, 110, 20)) +
list(range(200, 1100, 200)) +
list(range(2000, 11000, 2000)) +
list(range(20000, 110000, 20000)) +
list(range(200000, 1000000, 200000))
)
distances_quadratiques_moyennes = [] # Liste pour stocker les distances quadratiques moyennes
distances_theoriques = [] # Liste pour stocker les distances théoriques
# Simulation pour chaque nombre de pas
for NBR_PAS in liste_NBR_PAS:
positions_finales = [] # Liste pour stocker les positions finales des ivrognes
# Simulation des ivrognes for _ in range(NBR_IVROGNES):
position = 0 # Position initiale
# Simulation des pas pour un ivrogne for _ in range(NBR_PAS):
pas = random.choice([-1, 1]) # Choix aléatoire d'un pas (-1 ou 1)
position += pas # Mise à jour de la position
positions_finales.append(position)
# Calcul de la distance quadratique moyenne pour ce nombre de pas
distances_quadratiques = [pos**2 for pos in positions_finales]
distance_quadratique_moyenne = sum(distances_quadratiques) / NBR_IVROGNES
distances_quadratiques_moyennes.append(distance_quadratique_moyenne)
# Calcul de la distance théorique
distance_theorique = NBR_PAS # Pour une marche aléatoire simple en 1D
distances_theoriques.append(distance_theorique)
# Conversion en tableaux numpy pour faciliter le tracé
liste_NBR_PAS_np = np.array(liste_NBR_PAS)
distances_quadratiques_moyennes_np = np.array(distances_quadratiques_moyennes)
distances_theoriques_np = np.array(distances_theoriques)
# Création du graphique
plt.figure(figsize=(8, 5))
plt.plot(liste_NBR_PAS_np, distances_theoriques_np, '--', label='Théorie')
plt.plot(liste_NBR_PAS_np, distances_quadratiques_moyennes_np, 'o', label='Simulation', markeredgewidth=2, markersize=2)
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Nombre de pas (échelle logarithmique)', fontsize=14)
plt.ylabel('Distance quadratique moyenne $\\langle x^2 \\rangle$', fontsize=14)
plt.title('$\\langle x^2 \\rangle$ = f(nombre de pas) (Python Simple)', fontsize=15)
plt.legend()
plt.grid(True, which="both", ls="--")
plt.figtext(0.70, 0.015, 'www.sciences-physiques.net', fontsize=6, color='black', alpha=0.9, fontweight='normal')
plt.show()

Conclusion#
La distance quadratique moyenne parcourue par l’ivrogne est proportionnelle à
Annexes#
Mathématiques#
Intégrale #
La première intégrale à calculer est :
En prenant au carré l’intégrale
On s’empresse de passer en coordonnée polaire :
Que l’on sait calculer facilement après un changement de variable (
La racine carrée donne le résultat de l’intégrale :
Intégrale #
Or l’intégrale
Compléments sur la Gaussienne#
Une distribution gaussienne classique a la forme :
l’espérance
Dans le cas de cet article, la gaussienne est centrée en 0 (
Formule de Stirling#
L”approximation de Stirling est une formule qui donne une estimation de la factorielle d’un grand nombre
La factorielle d’un entier naturel
Pour des valeurs de
Logarithme du factorielle
Pour faciliter les manipulations mathématiques, il est souvent utile de travailler avec le logarithme de la factorielle plutôt que la factorielle elle-même. En prenant le logarithme naturel de
Cette somme peut être difficile à calculer directement, mais pour de grandes valeurs de
Comme
Pour de grandes valeurs de
Ajout du terme de correction avec la formule d’Euler-Maclaurin
La formule d’Euler-Maclaurin est donnée par :
sont les nombres de Bernoulli est le reste après termes.
Pour notre approximation, nous négligeons les termes d’ordre supérieur (de plus les dérivées impaires de
Revenons à
Méthode de Laplace pour approximation plus précise
L’approximation de Stirling complète inclut un facteur
La factorielle est liée à la fonction Gamma par :
Nous allons appliquer la méthode de Laplace à cette intégrale :
Trouver le maximum de
Le développement de Taylor de
L’intégrale devient :
Remarque : Nous avons étendu les bornes d’intégration à
L’intégrale est une intégrale gaussienne connue :
En combinant les résultats, nous obtenons :
Comme
Physique#
Démonstration avec la formule de Stirling#
Pour calculer la probabilité que l’ivrogne se retrouve en position
Approximation de Stirling
Pour des grands nombres
Calcul du logarithme de la probabilité
Substituons ces expressions dans
Ecriture avec les grandeurs du problème
Nous pouvons écrire
Développement limité pour
Lorsque
Voici le développement de Taylor de
Le développement de Taylor de
Calculons chaque terme séparément de
Premier terme :
Deuxième terme :
Troisième terme :
Regroupement des termes :
Simplification des termes :
Les termes en
Les termes en
Les termes en
Les termes en
Les termes en
Ainsi
Probabilité
Ce résultat montre que la probabilité suit une distribution gaussienne centrée en
Facteur de normalisation
Pour normaliser la fonction, nous utilisons l’intégrale gaussienne :
Dans notre cas,
Le facteur de normalisation est donc
La probabilité de trouver l’ivrogne en position
Intérêt de l’approximation de Stirling ici
L’utilisation de l’approximation de Stirling est particulièrement utile lorsque le nombre de pas
Dans le cas de l’ivrogne :
Simplicité de calcul : Elle évite le calcul direct de factorielles de grands nombres, qui peut être complexe et impraticable.
Approche asymptotique : Elle fournit une approximation valable pour
, ce qui est souvent le cas dans les problèmes physiques et statistiques.Lien avec la loi normale : Elle permet de montrer que la distribution binomiale tend vers une loi normale lorsque
est grand, ce qui est une manifestation du théorème central limite.
Code#
Version vectorisée#
# Importation des bibliothèques nécessaires
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# Configuration des paramètres de Matplotlib pour les graphiques
matplotlib.rcParams['figure.dpi'] = 150 # Résolution des images
# Constantes
NBR_IVROGNES = 2000
liste_NBR_PAS = (
list(range(10, 110, 20)) +
list(range(200, 1100, 200)) +
list(range(2000, 11000, 2000)) +
list(range(20000, 110000, 20000)) +
list(range(200000, 1000000, 200000))
)
distances_quadratiques_moyennes = [] # Liste pour stocker les distances quadratiques moyennes
distances_theoriques = [] # Liste pour stocker les distances théoriques
# Simulation pour chaque nombre de pas
for NBR_PAS in liste_NBR_PAS:
# Génération de tous les pas aléatoires en une seule fois
pas = np.random.choice([-1, 1], size=(NBR_IVROGNES, NBR_PAS))
# Calcul des positions finales en sommant les pas
positions_finales = pas.sum(axis=1)
# Calcul de la distance quadratique moyenne pour ce nombre de pas
distances_quadratiques = positions_finales ** 2
distance_quadratique_moyenne = distances_quadratiques.mean()
distances_quadratiques_moyennes.append(distance_quadratique_moyenne)
# Calcul de la distance théorique
distance_theorique = NBR_PAS # Pour une marche aléatoire simple en 1D
distances_theoriques.append(distance_theorique)
# Conversion en tableaux numpy pour faciliter le tracé
liste_NBR_PAS_np = np.array(liste_NBR_PAS)
distances_quadratiques_moyennes_np = np.array(distances_quadratiques_moyennes)
distances_theoriques_np = np.array(distances_theoriques)
# Création du graphique
plt.figure(figsize=(8, 5))
plt.plot(liste_NBR_PAS_np, distances_theoriques_np, '--', label='Théorie')
plt.plot(liste_NBR_PAS_np, distances_quadratiques_moyennes_np, 'o', label='Simulation', markeredgewidth=2, markersize=2)
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Nombre de pas (échelle logarithmique)')
plt.ylabel('Distance quadratique moyenne $\\langle x^2 \\rangle$')
plt.title('$\\langle x^2 \\rangle$ = f(nombre de pas) (Vectorisé)')
plt.legend()
plt.grid(True, which="both", ls="--")
plt.figtext(0.70, 0.015, 'www.sciences-physiques.net', fontsize=6, color='black', alpha=0.9, fontweight='normal')
plt.show()

Version utilisant pytorch et CUDA (de NVidia)#
# Importation des bibliothèques nécessaires
import torch
import matplotlib
import matplotlib.pyplot as plt
# Configuration des paramètres de Matplotlib pour les graphiques
matplotlib.rcParams['figure.dpi'] = 150 # Résolution des images
# Détection du dispositif (CPU ou GPU)
dispositif = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"Utilisation du dispositif : {dispositif}")
# Constantes
NBR_IVROGNES = 2000
liste_NBR_PAS = (
list(range(10, 110, 20)) +
list(range(200, 1100, 200)) +
list(range(2000, 11000, 2000)) +
list(range(20000, 110000, 20000)) +
list(range(200000, 1000000, 200000))
)
distances_quadratiques_moyennes = [] # Liste pour stocker les distances quadratiques moyennes
distances_theoriques = [] # Liste pour stocker les distances théoriques
# Simulation pour chaque nombre de pas
for NBR_PAS in liste_NBR_PAS:
# Génération de tous les pas aléatoires en une seule fois sur le dispositif choisi
pas = torch.randint(0, 2, (NBR_IVROGNES, NBR_PAS), device=dispositif, dtype=torch.int8) * 2 - 1
# Calcul des positions finales en sommant les pas
positions_finales = pas.sum(dim=1)
# Calcul de la distance quadratique moyenne pour ce nombre de pas
distances_quadratiques = positions_finales.float() ** 2
distance_quadratique_moyenne = distances_quadratiques.mean().item()
distances_quadratiques_moyennes.append(distance_quadratique_moyenne)
# Calcul de la distance théorique
distance_theorique = NBR_PAS # Pour une marche aléatoire simple en 1D
distances_theoriques.append(distance_theorique)
# Conversion en tensors pour faciliter le tracé
liste_NBR_PAS_tensor = torch.tensor(liste_NBR_PAS)
distances_quadratiques_moyennes_tensor = torch.tensor(distances_quadratiques_moyennes)
distances_theoriques_tensor = torch.tensor(distances_theoriques)
# Création du graphique
plt.figure(figsize=(8, 5))
plt.plot(liste_NBR_PAS_tensor.numpy(), distances_theoriques_tensor.numpy(), '--', label='Théorie')
plt.plot(liste_NBR_PAS_tensor.numpy(), distances_quadratiques_moyennes_tensor.numpy(), 'o', label='Simulation',
markeredgewidth=2, markersize=2)
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Nombre de pas (échelle logarithmique)')
plt.ylabel('Distance quadratique moyenne $\\langle x^2 \\rangle$')
plt.title('$\\langle x^2 \\rangle$ = f(nombre de pas) (PyTorch)')
plt.legend()
plt.grid(True, which="both", ls="--")
plt.figtext(0.70, 0.015, 'www.sciences-physiques.net', fontsize=6, color='black', alpha=0.9, fontweight='normal')
plt.show()
