Newer
Older
# 9 janvier 2025
Modification des sorties `[u]` pour avoir, à chaque tour,
le nombre de vendeurs viables, par type de matière
première vendue.
Sorties des traces des simulations, pour les flux de matières premières, les clients et les vendeurs (agrégées au moment des changements de stratégies et en fin de simulation).
# 27 novembre 2024
Refonte du modèle : introduction des matières premières
extraites et recyclées.
# 27 septembre 2024
Ajout du calcul de pondération en fonction du nombre de clients
depuis le début de la simulation (POND_MODE 4), ce qui n'est pas
le nombre de ventes (POND_MODE 1).
Ce mode converge très difficilement.
# 24 septembre 2024
Correction d'un bug : la pondération petits / gros vendeurs
omettait la soustraction de la pondération de ce vendeur
à la somme des pondérations, lorsqu'il n'y avait pas affaire
avec ce vendeur.
# 17 septembre 2024
Version utilisée pour les diagrammes de la réunion du 24/09/24.
Qualité est devenue continue.
Disparition du seuil, qui devient identique pour tous les vendeurs.
Modifications sur les pondérations :
- La fidélité est désactivée. Ainsi on peut faire tourner le modèle
sans contraintes et ajouter les biais pour observer les changements.
- Une pondération qui favorise les plus petits vendeurs et les plus gros
est activable. Pour le moment basée sur le nombre de ventes depuis
le début de la simulation.
Cette pondération est celle d'une courbe (bx - a)² + c
(de mémoire. c'est pê ax-b…), les paramètres a,b,c sont dans
la fonction init() des clients.
- Et on peut désactiver pour n'avoir qu'un tirage aléatoire.
Il est possible d'avoir la trajectoire dans les sorties (c'est vite
très verbeux, il faut limiter le nombre de simus).
Tout ça se commande à partir du fichier congig.h qui devient un peu
touffu. Mais il est très documenté.
Le tracé de la matrice de transition permet un tracé de courbe de
chaleur. Les paramètres ont un peu changé (c'est documenté
tant bien que mal).
# 3 septembre 2024
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
Version GPU.
Le code a été réécrit en se basant sur les librairies CUDA.
La structure du code a été changée. La boucle principale est dans `main.cu`.
Les sorties sont sous la même forme que précédemment à quelques petites
modifications près ; on retrouve les lignes `[i]`, `[t]`, `[b]` et `[q]`.
Un *seuil_min* a été ajouté, qui peut être mis à 0.
## Compilation et exécution
Pour commencer, éditer le fichier `config.h` qui contient les paramètres
des simulations. Le fichier est commenté, en espérant que ces commentaires
soient suffisamment compréhensibles.
La distribution de la population des clients est dans `stats.h` qui
contient le tableau de la répartition des revenus par ménage en 2018.
```bash
# Compilation
nvcc main.cu -o ccsyl
# Exécution avec sortie à chaque tour
./ccsyl | tee resultats.txt | grep '^\[t'
```
# Pistes d'amélioration
L'exécution sollicite la carte graphique et un coeur du processeur.
On se rend compte que la partie du processeur comprend ce qui n'est
pas parallélisable, et qu'il constitue un nouveau goulot d'étranglement.
Donc toute optimisation à ce niveau a un impact important.
En particulier il y a quelques additions de tableaux qui pourraient
faire l'objet d'un algorithme de type reduce. Celui-ci est proposé
dans les outils CUDA.
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
# 23 août 2024
## Nouvelle branche
Le commit d'aujourd'hui sera suivi de la création d'une
nouvelle branche ; le modèle commençant à se préciser,
des simulations en masse sont à prévoir.
Le présent code parallélise les simulations
sur les différents cœurs à l'aide de la librairie openmp,
mais étant donné que le code des clients est plutôt
simple, il serait beaucoup plus efficace de le paralléliser
sur un GPU. C'est ce qui sera fait sur la branche master,
tandis que la v1 contient le code actuel sur openmp.
## Matrices de transition
L'étude des classes de qualité, de marges et de seuils
se voit étoffée du tracé des matrices de transition.
Sur l'axe vertical, on a les classes à l'état initial,
et sur l'axe horizontal on a les classes à la fin
de la simulation. Seules les simulations ayant convergé
sont représentées.
Celles-ci sont calculées et tracées dans
[[classes/matrice_transition.scm]] :
```sh
cd classes/
emacs matrice_transition.scm
# Il faut renseigner V : nombre de vendeurs,
# Q : nombre de classes de qualité, et _COL_A_AFFICHER
# (_COL_Q : qualité, _COL_M : Marges et _COL_S : seuils),
# puis :
xzcat ../v5q4-100k-cs0.5.txt.xz | \
guile -s matrice_transition.scm gnuplot norm | gnuplot
```
La configuration n'est pas des plus ergonomiques, désolé,
je n'avais pas fait de scheme depuis longtemps.
Ici on a utilisé l'argument *gnuplot*, qui génère une sortie
qui peut être directement pipée sur gnuplot
pour la visualisation. Sans l'argument *gnuplot*, on obtient
simplement la matirce sur la sortie standard.
L'argument *norm* normalise la matrice ligne par ligne.
Il est également disponible sans le mode *gnuplot*.
La lecture des arguments est rigide : il faut donner
les arguments dans l'ordre et exactement comme attendu.
# 5 août 2024
## Fidélité relative
(Voir le chapitre “choix du vendeur” au *21 juin 2024*)
Plutôt que d'utiliser le coefficient de fidélité d'un client
pour un vendeur, qui ne tient pas compte de ce coefficient
pour les autres vendeurs (et pour le même client), il semble
plus intéressant de considérer la probabilité que ce vendeur
soit choisi en priorité par ce client.
C'est ce qu'on appelle la fidélité relative du client pour
ce vendeur.
## Classes de qualités
Le projet est de donner des résultats par « classe de qualité ».
On veut, dans les sorties, avoir l'effectif des vendeurs pour chaque qualité.
Exemple :
| *qualité* | 1 | 2 | 3 | 4 |
|----------:|--:|--:|--:|--:|
| Simu 1 | 2 | 0 | 1 | 2 |
| Simu 2 | 1 | 1 | 2 | 1 |
| Simu 3 | 1 | 2 | 2 | 0 |
| (…) | | | | |
On dira que (2, 0, 1, 2) est la classe de qualités de la première simulation.
On espère, sur un nombre de simulations suffisamment important, voir
s'il y a des aggrégats et des manques dans les classes de qualités.
À noter qu'on pourra tenter la même chose sur d'autres valeurs que la qualité
(il suffira de les discrétiser). Dans un premier temps on discrétisera
marge et seuils en autant de valeurs que la qualité.
### Sorties
Dans les sorties, les résultats par classes de qualités
sont donnés par les lignes commençant par `[q]`.
Parce qu'il est intéressant de comparer la distribution des classes de qualités
avant et après la simulation, les classes de qualité de la population telle
qu'elle est répartie au début de la simulation sont écrites aussi, dans les

BERNARD Stephan
committed
colonnes de même nom commençant par `I_`.
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
### Nombre de simulations
Si on prend Q = nombre de classes de qualité et V = nombre de vendeurs,
le nombre de combinaisons possibles n'est pas trivial.
Si on note $N_V^Q$ le nombre de classes pour $V$ vendeurs
et $Q$ qualités possibles, on a :
* $N_V^1 = 1$
* $N_1^Q = Q$
* $N_V^Q = N_{V-1}^Q + N_V^{Q-1}$
Pour expliquer cette dernière formule, prenons par exemple $D_4^3$
*(désolé pour l'absence de rigueur dans la notation, il a été choisi de*
*privilégier la compréhension visuelle)* :
$$D_4^3 = \begin{matrix}
(0 & 0 & 4)\\
(0 & 1 & 3)\\
&\vdots&\\
(3 & 1 & 0)\\
(4 & 0 & 0)
\end{matrix}$$
En ajoutant une colonne (donc une qualité), on obtient
*(la séparation en deux est là pour bien distinguer deux parties,*
*mais c'est à lire ligne par ligne, de la même façon qu'au-dessus)* :
$$D_4^{3+1} = \begin{matrix}\begin{bmatrix}
0 & (0 & 0 & 4)\\
0 & (0 & 1 & 3)\\
\vdots & &\vdots&\\
0 & (3 & 1 & 0)\\
0 & (4 & 0 & 0)
\end{bmatrix}\\
\begin{Bmatrix}
1 & 0 & 0 & 3\\
\vdots & &\vdots&\\
1 & 3 & 0 & 0\\
2 & 0 & 0 & 2\\
\vdots & &\vdots&\\
\end{Bmatrix}\end{matrix}$$
Dans la partie entre crochets [], on a simplement une colonne de 0
devant $D_4^3$ (on a laissé les parenthèses exprès pour reconnaître $D_4^3$).
Quant à la partie entre accolades, si on soustrait 1 à toutes les valeurs
de la première colonne, on a exactement $D_3^4$.
Une démonstration plus rigoureuse reste à produire (la propagation
récursive d'une hypothèse d'absurdité semble tendre les bras).
Compte-tenu de l'écriture récursive du calcul du nombre de classes, son écriture
dans un langage à parenthèses va de soi. Je ne résiste pas à l'envie
d'en copier-coller le code (en *scheme*, donc) :
```clisp
(define card
(lambda (v q)
(if (= q 1)
1
(if (= v 1)
q
(+ (card v (1- q)) (card (1- v) q))))))
```
Pour 5 vendeurs et 4 qualités, on a donc 56 classes de qualité.
Pour 10 vendeurs on passe à 286 classes.
Le code pour compter les combinaisons de classes est dans un répertoire
`classes/`. Il est composé de `classes.scm` qui contient les outils
pour générer ou compter les combinaisons de classes et de `classes_main.scm`
qui permet de lire les fichiers résultats de simulations.
### Combinaisons de classes
Les classes de qualités ne sont pas équiprobables. Par exemple, s'il n'y a
qu'une façon d'obtenir la classe (0 5 0 0) (tous les vendeurs vendent la
qualité 2), il y a plusieurs façons d'obtenir la classe (4 0 0 1) :
soit le vendeur 1 vend la qualité 4 et les autres vendent la qualité 1,
soit c'est le vendeur 2 qui vend la qualité 4 et les autres la qualité 1, ….
On a en tout 5 possibilités d'obtenir la classe (4 0 0 1) contre une seule
d'obtenir (0 5 0 0). On dira qu'il y a 1 combinaison pour la classe (0 5 0 0)
et 5 combinaisons pour la classe (4 0 0 1).
Dans le processus de simulation, les tirages aléatoires rendent équiprobables
chaque combinaison. Par conséquent les classes de qualité ne le sont pas.
On associe donc aux sorties le nombre de combinaisons à chaque classe de qualité.
### Simulations
Voici les paramètres du dernier commit d'aujourd'hui (14 août 2024), à partir
desquels on donne les premières interprétations :
- On fait 10240 simulations, soit 10 fois le nombre de combinaisons de classes.
- On a 5 vendeurs et 250 clients. C'est peu, notamment pour le nombre de
vendeurs, mais il s'agit avant tout de tester.
- On a 4 qualités possibles, et on discrétisera les seuils et marges en
autant de classes.
- Les vendeurs changent de stratégie après 10 déficits successifs.
- On termine la simulation après 100 itérations sans déficit, et on limite
le nombre de pas de temps à 2100 (2000, mais on refait 100 itérations sans
changement de stratégie commerciale avant d'afficher les résultats).
On a augmenté le nombre d'itérations sans déficit pour s'assurer d'une vraie
stabilisation du système avant d'écrire les résultats.
- Les pondérations des vendeurs sont plafonnées à 50 et un vendeur qui change
de stratégie commerciale distribue aléatoirement 2 points de pondération
aux clients.
- Le coefficient de survie des vendeurs est de 0,5. Celui-ci sert à déterminer
le seuil maximum, qui est égal à la somme des budgets des clients multiplié
par le coefficient de survie et divisé par le nombre de vendeurs.
- La marge maximum des vendeurs est de 10 (le coût de fabrication étant égal
à la qualité, donc entre 1 et 4).
- Le budget des clients est distribué selon la répartition du plafond de revenus
par ménage et par centiles en 2018. Le budget d'un client est strictement
supérieur au plus bas coût de fabrication.
- Les valeurs initiales des vendeurs sont tirées aléatoirement. Précédemment,
ceux-ci étaient initialisés aux valeurs maximales. On est passé à un tirage
aléatoire pour plusieurs raisons :
* vérifier dans l'état initial qu'on obtient bien les valeurs théoriques
d'effectifs de classes,
* observer les différences entre les résultats en fin de simulation
et les valeurs moyennes pour faire émerger des phénomènes,
* gommer la prime à l'état initial qui résulte d'une initialisation toujours
identique.
### Premiers résultats
Étant toujours en cours de développement de l'outil de simulation, il s'agit
ici simplement d'observations effectuées sur des simulations effectuées avec
des jeux de paramètres allégés. Il est trop tôt pour en tirer des conclusions.
Néanmoins, on a pu observer :
- une tendance à converger plus facilement dans les classes de faibles qualités
(et donc de faibles coût de fabrication),
- cette même tendance est encore plus forte en ce qui concerne les seuils,
- en revanche, les classes de marges moyennes sont favorisées.
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# 21 juin 2024
## État actuel
On a un truc qui tourne et qui donne des résultats, et on explore.
## Fonctionnement
### Vendeurs
On a $\gamma + 1$ (actuellement 5) vendeurs qui vendent des ***trucs***.
Le vendeur $i$ vend des trucs qui ont :
- une certaine **qualité** $q_i$, ($q_i \in \{1,2,3,4\}$);
- un **coût** de production $c(q_i)$ (égal à la qualité : produire un truc
de qualité 1 coûte 1฿[^1], 2฿ pour la qualité 2, *etc…*).
- Sur un truc, le vendeur $i$ se fait une **marge** $m_i$,
- et du coup il le vend à un certain **prix** : $p_i = m_i + c(q_i)$.
[^1]: Le symbole ฿ est le symbole monétaire du Baht thaïlandais, utilisé en remplacement du symbole du *Balle familier* (qui prend une paire de barres) qui n'est pas dans les polices UTF-8 puisqu'il n'existe pas et c'est bien dommage.
### Pijaca
*Pijaca* (ou Пијаца, prononcer « piyatsa ») signifie *marché* en serbe, dans le
[second sens donné par le Larousse](https://www.larousse.fr/dictionnaires/francais/march%C3%A9/49391),
à savoir « Réunion de commerçants ambulants qui, à jours fixes,
vendent dans un lieu dépendant du domaine public des produits comestibles,
des articles ménagers, vestimentaires, etc. ».
C'est pour ne pas le confondre avec les 7 autres sens français du mot
qu'on utilise le mot Serbe.
Notre pijaca est un marché aux trucs.
Voici les règles du pijaca :
- Tous les vendeurs sont présents.
- Tous les clients sont présents.
- Les vendeurs ont suffisamment de stock de truc pour répondre
à toutes les sollicitations des clients.
- Si un client ne fait pas affaire, c'est parce qu'aucun vendeur
n'est en capacité de satisfaire sa demande (le fonctionnement
des clients est décrit plus loin).
- Lorsqu'un client sollicite un vendeur, si celui-ci est en mesure
de satisfaire sa demande alors la transaction se fait,
**au prix du vendeur**.
À l'issue du pijaca, tous les clients qui peuvent être satisfaits
ont fait affaire.
### Vendeurs (suite)
À la fin d'un jour de pijaca, les vendeurs ont vendu
un certain nombre de trucs. Si le vendeur $i$
a vendu $N_i$ trucs, il a fait :
- un **chiffre d'affaires** $Ca_i = N_i * p_i$,
- un **bénéfice** $B_i = N_i.m_i$.
Pour que le vendeur $i$ soit *viable* (c'est-à-dire qu'il peut vivre
de son activité commerciale), il faut que son bénéfice soit supérieur
à un **seuil** $S_i$.
On considère qu'il existe un fond autogéré des vendeurs (le FAVEUR)
pour les vendeurs déficitaires. Le règlement du FAVEUR dit qu'au bout
d'un certain nombre (10) de jours de pijaca successifs de déficit,
le vendeur change sa stratégie commerciale. Quand il en a changé,
il faut le même nombre de jours de déficit successifs pour en changer
à nouveau.
#### Stratégie commerciale
Un changement de stratégie commerciale consiste à changer
une et une seule de ces trois valeurs :
- qualité,
- marge,
- ou seuil.
Le choix de la valeur à changer se fait de façon aléatoire,
avec un tirage équiprobable.
### Clients
Un client $j$ à un **besoin** $n_j$, qui est un nombre de trucs
qu'il souhaite aquérir à chaque jour de marché. Actuellement
$n_j = 1, \forall j$.
Ce même client a un **budget** $b_j$.
Tous les clients peuvent s'acheter au moins un truc
qui serait vendu au coût de fabrication de la qualité
la moins chère. On a donc défini : $\forall j, b_j > c(1)$.
#### Choix du vendeur
À chaque jour de pijaca, les clients choisissent l'ordre dans
lequel ils vont voir les vendeurs. Dès qu'un vendeur est en
mesure de satisfaire le besoin du client en respectant son budget,
l'affaire est faite et le client ne va pas voir d'autre vendeur
ce jour-là.
Le choix de l'ordre des vendeurs qu'un client va voir se base
sur un vecteur d'évaluation des vendeurs par le client,
qu'on appelle **vecteur des pondérations**. On le note
$\overrightarrow{P_j} = (p_{j,0}\;;\;p_{j,1}\;;\;…)$.
Initialisé à $\overrightarrow{0}$, le principe est que lorsque
le client $j$ rencontre le vendeur $i$, alors $p_{j,i}$ est :
- incrémenté si le client et le vendeur font affaire,
- décrémenté sinon.
Le prochain vendeur que le client $j$ va rencontrer est issu
d'un tirage aléatoire pondéré par les valeurs $p_{j,i}$.
Si $\overrightarrow{P_j} = \overrightarrow{0}$ alors on
effectue un tirage équiprobable.
Si le client $j$ choisit de rencontrer le vendeur $i$ et que
celui-ci ne peut le satisfaire, alors $p_{j,i}$ est
décrémenté, et on effectue un nouveau tirage en considérant le vecteur
$\overrightarrow{P_j}$ dans lequel on ignore la valeur $p_{j,i}$.
Ceci est répété jusqu'à ce que le client fasse affaire
ou jusqu'à ce que tous les vendeurs aient été rencontrés.
##### Exemple
On considère le client 42, avec le vecteur de pondérations
$\overrightarrow{P_{42}} = (1\;\;3\;\;0)$.
Soit l'ensemble $E_{42} = \emptyset$.
- On a : $\sum_{i \in [0 ; \gamma]}^{i \notin E_{42}} p_{42,i} = 4$.
- On effectue un tirage aléatoire $\alpha \in ]0\;;\;4[$.
Supposons qu'on ait $\alpha = 1.35$.
- On cherche $v = min(k \in [0 ; \gamma]\,,\; k \notin E_{42})$ tel que
$\left(\sum_{i \in [0 ; k]}^{i \notin E_{42}}p_{42,i} ≥ \alpha \right)$
(ici $v = 1$ car :
- $1 < \alpha\;(k = 0)$
- et $1+3 ≥ \alpha\;(k = 1)$
- le plus petit $k$ qui convient est donc 1).
- Le client 42 rencontre donc le vendeur 1.
- Supposons que ce vendeur ne peut satisfaire son besoin. On décrémente donc
la pondération du vendeur 1, et $\overrightarrow{P_{42}}$ prend la valeur
$(1\;\;2\;\;0)$
- Le client va essayer un autre vendeur.
On ajoute 1 à $E_{42}$ et on reprend à la première étape :
- On a $\sum_{i \in [0 ; \gamma]}^{i \notin E_{42}} p_{42,i} = 1$
- On prendra donc $\alpha \in ]0\;;\;1[$ ce qui nous donne $v = 0$.
- Supposons que le vendeur 0 ne puisse lui non plus satisfaire
le client 42.
On décrémente donc la pondération du vendeur 0,
ce qui donne $\overrightarrow{P_{42}} = (0\;\;2\;\;0)$,
on ajoute 0 à $E_{42}$,
et le client va essayer un autre vendeur.
- Il ne reste que le vendeur 2, qui est sélectionné malgré sa pondération
égale à 0.
- Si le vendeur 2 peut satisfaire le client, alors à l'issue de ce jour
de marché $\overrightarrow{P_{42}}$ aura
la valeur $(0\;\;2\;\;1)$,
##### Remarques
###### Pondérations négatives
- Si un vendeur a une pondération de 0 et ne peut faire affaire,
alors sa pondération est décrémentée. On incrémente ensuite
toutes les pondérations pour faire en sorte que toutes les
pondérations soient positives (ou nulles).
Par exemple, si on devait décrémenter le vendeur 2 lorsque
$\overrightarrow{P_{42}} = (1\;\;3\;\;0)$, on obtiendrait
le vecteur $(2\;\;4\;\;0)$.
###### Vecteurs de pondérations nulles
- Un client qui a un vecteur de pondérations égal à
$\overrightarrow{0}$ et qui ne fait affaire avec aucun vendeur
aura toujours à l'issue du marché le vecteur de pondérations
$\overrightarrow{0}$.
- En revanche, si, avec un vecteur de pondérations $\overrightarrow{0}$,
le client fait affaire, alors, à l'issue du jour de marché :
- les vendeurs avec lesquel il n'a pas fait affaire ont une pondération de 0,
- les vendeurs qu'il n'a pas vus ont une pondération de 1,
- le vendeur avec lequel il a fait affaire a une pondération de 2.
- Dans le cas particulier où le client avec un vecteur de pondérations
nulles fait affaire avec le premier vendeur qu'il rencontre,
celui-ci aura une pondération de 1 et les autres vendeurs une pondération
nulle. Ce client visitera donc le même vendeur en premier lieu
lors du prochain jour de marché. Tant qu'il fera affaire, il n'ira voir
aucun autre vendeur.
## Simulations
### Conditions initiales
Pour une simulation, une population de clients (500) et de vendeurs (5)
est générée.
- On fixe une marge maximum $Ma_{max}$ (10฿)
- On prend les données du
[revenu disponible en pourcentage cumulé des ménages en france](https://www.insee.fr/fr/statistiques/5371205?sommaire=5371304),
pour l'année 2018.
En voici la courbe :

On notera que les cinq derniers centiles ne sont pas donnés.
On fera donc comme si c'était des quatre-vingt-quinziles.
- On calcule un facteur de renormalisation des budgets à partir de
la dernière valeur $Rev_{max}$ du tableau des déciles :
on pose $coef_{budget} = \frac{Ma_{max}+c(q_{max})}{Rev_{max}}$.
Ainsi on s'assure qu'un budget du dernier quantile pourra payer
un truc au prix maximum, avec en plus une marge égale à $c(q_1)$.
- Pour chaque client :
- on fixe son besoin à 1 ($n_j = 1$)
- on tire aléatoirement un quantile. Soit $v_{quant}$ le budget
correspondant à ce quantile. On affecte
$b_j = c(q_1) + (v_{quant} . coef_{budget})$
- le vecteur des pondérations est initialisé à 0.
- Partant du principe qu'un truc qui arrive sur un marché vierge
est d'abord très cher, avant que son prix ne baisse,
on intitialise tous les vendeurs aux qualité, marge et seuil
maximaux.
Une fois tout ceci initialisé, on simule des jours de marché.
### Conditions d'arrêt
La condition d'arrêt est que tous les vendeurs soient viables.
On pourrait stopper le modèle à ce moment précis, mais on a ajouté
une valeur **nb_stop** (égale à 10) pour :
- lisser l'état des vendeurs comme sorties du modèle sur plusieurs
itérations (sans changement de stratégie) pour estomper l'effet
aléatoire,
- permettre au dernier vendeur ayant changé sa stratégie d'avoir
quelques itérations dans cette stratégie (à priori ce vendeur
n'était pas viable auparavant et n'a pas forcément
de clientèle vraiment fidélisée)
- s'assurer que l'arrêt n'est pas dû à un tirage accidentel.
Pendant ces quelques itérations les changement de stratégie
n'ont plus lieu.
Au bout d'un certain nombre d'itérations (2000), on arrête la simulation
(après *nb_stop* itérations supplémentaires), considérant qu'on
n'atteindra pas de situation de viabilité pour tous les vendeurs.
### Réplication
Cette simulation peut être répétée plusieurs fois :
- avec la même population initiale (seul le vecteur des pondérations
est réinitialisé). On parle alors de réplicat.
- En tirant une nouvelle population.
### Sorties du modèle
Les sorties du modèles se font dans un fichier ayant pour chaque ligne
le format suivant :
- 4 caractères : [, une lettre, ] et une espace. Ex : «[b] ».
Ceux-ci servent identifier la nature de ce que contient la ligne.
Actuellement, `[i] ` désigne les paramètres d'initialisation du modèle,
`[t] ` les informations relatives à une simulation,
`[b] ` le bilan d'une simulation.
- les données, au format csv, en utilisant un caractère de tabulation
pour délimiter les colonnes. Une première ligne donne les en-têtes
des colonnes.
Ainsi, on peut extraire au format csv la partie qui nous intéresse.
Par exemple :
```bash
# À l'exécution, on aime bien savoir à quelle simulation on en est,
# et comment se sont passées les simulations précédentes :

BERNARD Stephan
committed
OMP_NUM_THREADS=16 ./ccsyl | tee result.txt | grep '^\[t'
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
# Après l'exécution, on récupère les bilans des simulations :
cat result.txt | grep '^\[b' | cut -c5- > bilans.csv
```
La richesse des résultats possibles fait que les valeurs retournées
par les simulations varient en fonction des éléments
que l'on souhaite voir à un moment donné.
Notons toutefois deux éléments que l'on retrouve
dans tous les jeux de résultats :
- IdSimu : est un identifiant unique permettant d'identifier une exécution
d'un lot de simulations (désolé pour l'ambiguïté sud le terme "simu").
Précisément il est le nombre de millisecondes écoulées entre le moment
où a été lancé ce jeu de simulations et un instant précis lors du
développement où j'ai lancé une commande pour savoir le nombre
de millisecondes écoulées entre cet instant et l'*epoch unix*.
- NoSimu : dans un lot de simulations, chaque simulation est numérotée.
Ces deux éléments permettent de faire des jointures entre les différents
jeux de sorties (`[b]`, `[t]`, `[v]` ou `[c]` par exemple — parce qu'à un
moment on écrivait l'état de chaque vendeur et de chaque client à chaque
pas de temps en utilisant `[v]` et `[c]`).
# 8 juillet 2024
Il a été décidé de plafonner la valeur de fidélité. Avoir une fidélité à 500
n'a pas beaucoup de sens, 50 points de fidélité correspondant quasiment
à un écart irattrappable. Il a donc été implémenté un plafond au-delà
duquel une pondération cesse d'être incrémentée.
# 9 juillet 2024
On ajoute deux points d'impact marketing à chaque changement de stratégie.
Autrement dit, un vendeur qui change de stratégie marketing s'attribue un
point de pondération à deux clients tirés aléatoirement. Ces deux points
d'impact paraissent peu, mais influent beaucoup sur la convergence des
simulations.