\section{Implémentation} \subsection{Architecture Logicielle} Le projet est implémenté selon une architecture client-serveur moderne: \begin{itemize} \item \textbf{Backend}: Python 3.12 + FastAPI \item \textbf{Frontend}: React + TypeScript + Material-UI \item \textbf{Monorepo}: Structure Turborepo pour gestion unifiée \end{itemize} \subsection{Backend - Simulation Événementielle} \subsubsection{Architecture du Simulateur} Le simulateur utilise une approche \textbf{événementielle discrète}: \begin{lstlisting}[language=Python, caption=Structure principale du simulateur] class Simulator: def __init__(self, config: SimulationConfig): self.event_queue = [] # File de priorite (heapq) self.coordinator = MMOneQueue("coordinator", mu_c) self.servers = {id: MMOneQueue(id, mu_i) for ...} self.router = Router(p, [q1, q2, ...]) def run(self) -> SimulationResults: # Echauffement (warmup) while time < warmup_time: process_events() # Collecte statistiques while time < simulation_time: process_events() collect_time_series() # Toutes les 1000 unites return generate_results() \end{lstlisting} \subsubsection{Types d'Événements} Deux types d'événements sont gérés: \begin{enumerate} \item \textbf{ARRIVAL}: Arrivée d'une requête externe au coordinateur \begin{itemize} \item Ajout à la file du coordinateur \item Démarrage du service si coordinateur idle \item Planification de la prochaine arrivée (exponentielle) \end{itemize} \item \textbf{SERVICE\_END}: Fin de service à une station \begin{itemize} \item Retrait de la requête de la station \item Décision de routage (probabiliste) \item Envoi vers destination ou sortie système \item Démarrage du service suivant si file non vide \end{itemize} \end{enumerate} \subsubsection{Génération Aléatoire} Les nombres aléatoires exponentiels sont générés par transformation inverse: \begin{equation} X \sim \text{Exp}(\lambda) \Rightarrow X = -\frac{1}{\lambda}\ln(1-U), \quad U \sim \mathcal{U}(0,1) \end{equation} \begin{lstlisting}[language=Python, caption=Génération exponentielle] def exponential_random(rate: float) -> float: """Generation nombre aleatoire exponentiel""" return -math.log(1 - random.random()) / rate \end{lstlisting} \subsubsection{Routage Probabiliste} Le routage depuis le coordinateur utilise la méthode de sélection par inversion: \begin{lstlisting}[language=Python, caption=Routage probabiliste] def route_from_coordinator(self) -> Optional[str]: """Decide destination depuis coordinateur""" r = random.random() # Sortie du systeme avec probabilite p if r < self.exit_prob: return None # Selection serveur selon q_i cumulative = self.exit_prob for i, (server_id, prob) in enumerate(...): cumulative += prob if r < cumulative: return server_id \end{lstlisting} \subsubsection{Collecte des Statistiques} Trois types de données sont collectés: \begin{enumerate} \item \textbf{Métriques agrégées}: Temps moyens, utilisations, compteurs \item \textbf{Séries temporelles}: Échantillonnage périodique (1000 unités) \begin{lstlisting}[language=Python, caption=Collecte séries temporelles] def collect_time_series_sample(self): total_customers = 0 for queue in all_queues: n = len(queue.waiting) + (1 if queue.busy else 0) total_customers += n self.timestamps.append(current_time) self.customers_in_system.append(total_customers) \end{lstlisting} \item \textbf{Histogrammes}: Distribution des temps de traitement (20 bins) \begin{lstlisting}[language=Python, caption=Génération histogramme] def create_histogram(data: List[float]) -> dict: bins = np.linspace(min(data), max(data), 21) frequencies, _ = np.histogram(data, bins) return { "bins": bins.tolist(), "frequencies": frequencies.tolist(), "mean": np.mean(data), "std_dev": np.std(data) } \end{lstlisting} \end{enumerate} \subsection{Module d'Analyse Analytique} Le module \texttt{analytics/jackson.py} implémente le théorème de Jackson: \subsubsection{Calcul des Taux d'Arrivée Effectifs} \begin{lstlisting}[language=Python, caption=Taux d'arrivée effectifs] def compute_effective_arrival_rates(config): """Calcule lambda_eff selon theoreme de Jackson""" lambda_external = config.arrival_rate p = config.coordinator_exit_probability # Lambda coordinateur: lambda/(1-p) = lambda/p lambda_coord = lambda_external / p # Lambda serveurs: lambda * q_i / p lambda_servers = {} for server in config.servers: lambda_i = lambda_external * server.routing_prob / p lambda_servers[server.id] = lambda_i return lambda_coord, lambda_servers \end{lstlisting} \subsubsection{Métriques M/M/1} \begin{lstlisting}[language=Python, caption=Calcul métriques M/M/1] def compute_mm1_metrics(lambda_eff, mu): """Metriques pour une file M/M/1""" rho = lambda_eff / mu if rho >= 1: return {"stable": False, "utilization": rho} L = rho / (1 - rho) W = 1 / (mu - lambda_eff) Wq = rho / (mu - lambda_eff) return { "stable": True, "utilization": rho, "average_customers": L, "average_time": W, "average_wait_time": Wq } \end{lstlisting} \subsection{Interface Web} \subsubsection{Architecture Frontend} \begin{itemize} \item \textbf{Framework}: React 18 + TypeScript \item \textbf{UI Library}: Material-UI (MUI) v5 \item \textbf{State Management}: Zustand \item \textbf{Charts}: Chart.js + react-chartjs-2 \item \textbf{Network Diagrams}: D3.js \item \textbf{Build}: Vite \end{itemize} \subsubsection{Composants Principaux} \begin{enumerate} \item \textbf{ScenarioSelector}: Sélection scénarios prédéfinis \item \textbf{ParameterPanel}: Configuration manuelle $\lambda$, $\mu_c$, $p$, $q_i$ \item \textbf{SimulationControl}: Démarrage/arrêt simulation \item \textbf{ResultsDisplay}: Affichage résultats (onglets) \begin{itemize} \item Métriques: Tableaux détaillés \item Visualisations: Graphiques avancés \item Comparaison: Tables comparatives sim vs analytique \end{itemize} \item \textbf{TimeSeriesChart}: Évolution nombre de clients \item \textbf{ProcessingTimeHistogram}: Distribution temps traitement \item \textbf{NetworkDiagram}: Topologie réseau (D3.js) \end{enumerate} \subsubsection{Flux de Données} \begin{enumerate} \item Utilisateur configure paramètres ou sélectionne scénario \item Frontend envoie requête POST à \texttt{/api/simulation/start} \item Backend exécute simulation (20-30 secondes) \item Résultats retournés avec time\_series et histogram \item Frontend calcule analytique via \texttt{/api/analytics/jackson} \item Comparaison via \texttt{/api/analytics/compare} \item Visualisations rendues avec Chart.js \end{enumerate} \subsection{Tests et Validation} \subsubsection{Tests Unitaires Backend} 21 tests pytest couvrant: \begin{itemize} \item Génération nombres aléatoires exponentiels (moyenne, reproductibilité) \item Simulation simple M/M/1 (validation contre formules) \item Détection systèmes instables \item Multi-serveurs avec routage \item Analyse Jackson (Little's Law, conservation probabilités) \end{itemize} \textbf{Résultat}: \texttt{21/21 tests PASSED} \subsubsection{Tests d'Intégration} 8 tests shell automatisés: \begin{enumerate} \item Backend health check \item Listing scénarios \item Exécution scénario \item Récupération résultats \item Analyse Jackson \item Frontend accessible \item CORS configuré \end{enumerate} \textbf{Résultat}: \texttt{8/8 tests PASSED} \subsection{Performance} \begin{table}[H] \centering \caption{Performance de l'implémentation} \label{tab:performance} \begin{tabular}{lll} \toprule \textbf{Métrique} & \textbf{Valeur} & \textbf{Commentaire} \\ \midrule Temps simulation & 15-30s & Pour 100,000 unités temps \\ Événements/seconde & $\sim$30,000 & Sur machine standard \\ Mémoire backend & <100 MB & Efficacité Python \\ Bundle frontend & 720 KB & gzip: 231 KB \\ Tests backend & 0.19s & 21 tests \\ \bottomrule \end{tabular} \end{table}