Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
\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}