Files
Rabbit-s-Hole/repport/SimulationLapin.tex
T

216 lines
8.2 KiB
TeX

\documentclass[11pt, a4paper]{article}
% Préambule : packages utiles
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage[a4paper, margin=2cm]{geometry}
\usepackage[table]{xcolor}
\usepackage{listings}
\usepackage{hyperref} % hyperref se charge en dernier
\graphicspath{ {./images/} }
\definecolor{codebg}{HTML}{F6F8FA}
\definecolor{codeframe}{HTML}{D0D7DE}
\definecolor{kw}{HTML}{CF222E} % mots-clés C
\definecolor{tp}{HTML}{0550AE} % types
\definecolor{str}{HTML}{0A3069} % chaînes
\definecolor{cmt}{HTML}{6E7781} % commentaires
\definecolor{prep}{HTML}{8250DF} % préprocesseur
\lstset{
language=C,
basicstyle=\ttfamily\small,
keywordstyle=\color{kw}\bfseries,
commentstyle=\color{cmt}\itshape,
stringstyle=\color{str},
backgroundcolor=\color{codebg},
frame=single,
rulecolor=\color{codeframe},
numbers=left,
numberstyle=\tiny\color{cmt},
numbersep=8pt,
breaklines=true,
showstringspaces=false,
tabsize=4,
captionpos=b,
% types et fonctions courantes du C
morekeywords={size_t, uint8_t, uint32_t, uint64_t, NULL,
malloc, free, printf, rand, srand,
sqrt, log, cos, sin, M_PI},
% directives du préprocesseur (le # reste gris, le mot est coloré)
emph={include, define, ifndef, ifdef, endif, pragma},
emphstyle=\color{prep}\bfseries
}
\title{Simulation de population de lapins \\ « Rabbit Hole »}
\author{Aubin DORIVAL \\ F2 -- Promo 28}
\date{\today}
\begin{document}
\maketitle
\begin{center}
\url{https://git.dukantic.fr/dukantic/Rabbit-s-Hole}\\[0.5cm]
\includegraphics[width=0.7\textwidth]{draw_rabbit.jpg}
\end{center}
\section{Introduction}
Le projet « Rabbit Hole » est une simulation de population de lapins.
Elle vise à simuler la croissance de cette population en suivant certaines
règles, tout en faisant abstraction d'autres paramètres. Tout au long du
projet, j'ai globalement conservé les conditions et les probabilités
fournies dans le sujet.
\section{Règles}
Tout d'abord, il faut définir les règles à suivre.
\begin{itemize}
\item taux de gestation de $50\%$ par mois ;
\item $3$ à $6$ bébés par gestation, répartis de manière uniforme ;
\item les bébés deviennent adultes entre le 5\ieme{} et le 8\ieme{} mois ;
\item les adultes meurent avec un taux de $40\%$ par an, auquel s'ajoute
$10\%$ par an à partir de 10 ans ;
\item les bébés meurent avec un taux de $65\%$ par an, soit environ
$5\%$ par mois pendant 7 mois en moyenne.
\end{itemize}
\begin{center}
\includegraphics[width=\textwidth]{rabbit's_rules.png}
\end{center}
\section{Structure de données}
Pour stocker les lapins, j'ai choisi de les classer par âge. En effet,
toutes les règles sont basées sur l'âge : il suffit donc de compter les
lapins par classe d'âge. Ma structure de données repose sur ce principe :
un tableau par sexe, dont l'indice correspond à l'âge, ainsi que le nombre
de lapines en gestation. Pour les bébés, j'ai exactement la même chose,
si ce n'est que l'indice représente le mois plutôt que l'année. Pour les
nombres, j'ai choisi un entier non signé de 128 bits (non disponible sur
toutes les plateformes) afin de limiter au maximum les dépassements
d'entier.
\begin{figure}[htbp]
\begin{lstlisting}[caption={Structure de données pour les lapins}, label={lst:struct}]
#define N_MATURE (16)
#define N_KITTEN (8)
typedef struct rabbit_hole_s {
__uint128_t male_mature[N_MATURE];
__uint128_t female_mature[N_MATURE];
__uint128_t female_litter;
__uint128_t kitten_male[N_KITTEN];
__uint128_t kitten_female[N_KITTEN];
} rabbit_hole_t;
\end{lstlisting}
\end{figure}
\section{Implémentation}
Pour la génération de nombres aléatoires, j'utilise le générateur
Mersenne Twister, associé à la méthode de Box-Muller. Dans un premier
temps, j'effectuais un tirage aléatoire pour chaque probabilité et pour
chaque lapin. Par exemple, pour la mort : pour chaque lapin, je tire un
nombre aléatoire et je décide s'il meurt ou s'il survit. Cette approche
était beaucoup trop lente : au bout de 9 à 10 ans simulés, les calculs
prenaient déjà trop de temps. Je me suis alors dit que toutes mes
probabilités suivaient des lois uniformes et que je pouvais donc les
approximer par des gaussiennes grâce à la méthode de Box-Muller.
Je n'utilise cette approximation que lorsque le nombre de lapins à
traiter dépasse 100.
\begin{figure}[htbp]
\centering
\begin{align*}
R_{n,1},\, R_{n,2} &\gets \text{nombres aléatoires} \\
X_1 &= \sqrt{-2 \ln R_{n,1}} \cdot \cos(2\pi R_{n,2}) \\
X_2 &= \sqrt{-2 \ln R_{n,1}} \cdot \sin(2\pi R_{n,2})
\end{align*}
\caption{Méthode de Box-Muller}
\label{fig:box-muller}
\end{figure}
La gaussienne générée par la méthode de Box-Muller est centrée en 0 et
réduite (écart type 1). Dans mon cas, j'ai besoin de la centrer sur le
nombre de lapins attendu. Pour cela, je calcule $\mu$, la moyenne de la
valeur attendue, ainsi que $\sigma$, l'écart type de la gaussienne.
\begin{figure}[htbp]
\centering
\begin{align*}
\text{Loi binomiale (survies, sexes) : } \mathcal{B}(n, p) \\
\mu_{\text{bin}} &= n \cdot p \\
\sigma_{\text{bin}} &= \sqrt{n \cdot p \cdot (1-p)} \\[4pt]
\text{Somme de $n$ lois uniformes (portées) : } \sum_{i=1}^{n} \mathcal{U}([a,b]) \\
\mu_{\text{unif}} &= n \cdot \frac{a+b}{2} \\
\sigma_{\text{unif}} &= \sqrt{\frac{n \cdot (b-a)^2}{12}} \\[4pt]
\text{Tirage Box-Muller : } X_0 \sim \mathcal{N}(0,1) \\
X_{\text{utilisable}} &= \mu + \sigma \cdot X_0
\;\sim\; \mathcal{N}(\mu, \sigma^2)
\end{align*}
\caption{Décalage de la gaussienne par Box-Muller}
\label{eq:decalage-gaussienne}
\end{figure}
\begin{figure}[htbp]
\begin{lstlisting}[caption={Code des naissances}, label={lst:naissance}]
if (rabbits->female_litter < 100) {
for (i = 0; i < rabbits->female_litter; i++) {
taille1 = 3 + (int)(4.0 * genrand_real2());
for (int k = 0; k < taille1; k++) {
if (genrand_real1() > 0.5) (*new_kitten_male)++;
else (*new_kitten_female)++;
}
}
}else {
ul_mu_k = 4.5*(double)rabbits->female_litter; // 4.5 = (b+a)/2
ul_sigma_k = sqrt(1.118 * (double)rabbits->female_litter); //(k*k-1)/12 = 1.118
gauss(x_gauss);
x_gauss[0] = CLAMP_BTW(x_gauss[0] * ul_sigma_k+ ul_mu_k, 0.0 , rabbits->female_litter * 9.0);
ul_mu_sex = x_gauss[0] * 0.5;
ul_sigma_sex = sqrt(ul_mu_sex * 0.5);
x_gauss[1] = CLAMP_BTW(x_gauss[1] * ul_sigma_sex + ul_mu_sex , 0.0, rabbits->female_litter * 9.0);
(*new_kitten_female) = (__uint128_t)roundl(x_gauss[1]) ;
(*new_kitten_male) = (__uint128_t)roundl(x_gauss[0] - x_gauss[1]);
}
\end{lstlisting}
\end{figure}
\section{Statistiques}
Pour collecter les statistiques, j'écris sur la sortie d'erreur (stderr)
au format CSV, puis je redirige cette sortie vers un fichier afin de
l'exploiter. J'inscris une nouvelle ligne chaque mois, contenant
l'ensemble des nombres de ma structure. Pour afficher les nombres en
\verb|__uint128_t|, il n'existe pas de format d'affichage par défaut,
contrairement à \verb|uint64_t| par exemple (\verb|%llu|) : il a donc
fallu réaliser un formatage manuel. Les graphiques obtenus permettent de
vérifier que les règles posées au départ sont bien respectées.
\begin{figure}[htbp]
\centering
\includegraphics[width=0.45\textwidth]{regle1_gestation}
\includegraphics[width=0.45\textwidth]{regle2_distribution}
\includegraphics[width=0.45\textwidth]{regle2_portees}
\includegraphics[width=0.45\textwidth]{regle3_maturation}
\includegraphics[width=0.45\textwidth]{regle4_mortalite_adultes}
\includegraphics[width=0.45\textwidth]{regle5_survie_kittens}
\caption{Vérification graphique des règles}
\label{fig:regles}
\end{figure}
\section{Utilisation de l'IA}
Pendant ce TP, l'IA a été utilisée pour :
\begin{itemize}
\item réaliser les graphiques (Python, avec NumPy et Matplotlib) ;
\item vérifier la cohérence des valeurs retournées par la simulation ;
\item m'aider à rédiger ce rapport (LaTeX, correction d'erreurs et de
formulations en français).
\end{itemize}
Pour le reste du TP, aucune utilisation n'a été faite.
\end{document}