SlideShare une entreprise Scribd logo
1  sur  642
Télécharger pour lire hors ligne
INF442 : Traitement des Données Massives
A1 : Introduction au calcul haute performance (HPC)
suivi d’une
introduction à C++
Frank Nielsen
nielsen@lix.polytechnique.fr
X2014
6 avril 2016
Frank Nielsen A1-1
La mission du cours INF442 est de ...
◮ concevoir et analyser des algorithmes parallèles (//) sur des clusters de
machines à mémoire distribuée
◮ implémenter ces algorithmes // en C++ avec le standard Message
Passing Interface, MPI
◮ débogguer et exécuter ces programmes // sur un des quatres clusters en
salles machines de l’X
Frank Nielsen A1-2
Objectifs du cours INF442
◮ acquérir le “raisonnement informatique” pour le modèle
de calcul parallèle sur mémoire distribuée
= INF431 : multi-fils sur mémoire partagée
◮ programmer en C++ en utilisant l’interface MPI pour Message Passing
Interface, et se servir d’un cluster de machines
→ 169 machines organisés en 4 clusters dans les salles informatiques
◮ se familiariser avec le monde du HPC et du Big Data et des sciences des
données
→ 3A PA INFO : parcours HPC ou parcours Science des Données, etc.
Frank Nielsen A1-3
6 avril Introduction au HPC et à C++ (pointeurs)
TD : C++, passages par réf/pointeurs, unix command line
13 avril Clustering hiérarchique, C++ STL & récursivité
TD : C++ STL, récursivité, regroupement hiérarchique
20 avril Introduction à MPI et topologie
TD : k-moyennes et clustering d’images
27 avril —— vacances printemps : 25 au 29 avril ——
4 mai k-Moyennes et JL k-Moyennes
TD : MPI
11 mai révisions PM, tri et MapReduce (culture)
B5 : contrôle sur machine (PM)
18 mai classification (k-NN)
détection de pourriels avec k-NN (avec MPI)
25 mai Algèbre linéaire et matrices
matrices (regression)
1er juin Graphes et topologie/communication
TD : topologie MPI (diffusion anneau/hypercube), graphes
8 juin contrôle classant (CC)
Frank Nielsen A1-17
Introduction au HPC
Frank Nielsen A1-18
Qu’est-ce que le Calcul Haute Performance, le HPC ?
◮ Sciences des super-ordinateurs (http://www.top500.org/)
Top 1 : National Super Computer Center à Guangzhou, Chine :
Tianhe-2 (MilkyWay-2)
3, 12 Millions de cœurs, 54, 9 Petaflops (1015, PFlops), 17, 8 Mega Watts,
1 MW = 100 e/h ∼ 1 Me/an
◮ mais auss green HPC évalue les performances en MFlops/Watt,
http://www.green500.org/
◮ Le HPC = domaine incluant paradigmes de programmation parallèle,
langages de programmation, outils logiciels, systèmes informatiques, avec
ses conférences dédiées (ACM/IEEE Super Computing), etc.
Frank Nielsen A1-19
HPC : le top 5 des super-ordinateurs dans le monde
LINPACK benchmark : Rmax = performance maximale obtenue
Rpeak = maximum théorique de performance.
http://www.top500.org/project/top500_description/
Frank Nielsen A1-20
En France, Total : Pangea SGI ICE X 2.3 PFlops
(pétascale), 2015
Vous pouvez tous louer facilement et à faible coût du calcul HPC grâce aux
services du cloud comme AMZ AWS, MS Azure, etc.
Frank Nielsen A1-21
Total en 2016 : Pangea SGI ICE X 6.7 PFlops (pétascale)
stockage = 26 pétaoctets (≡ 6 millions de DVDs)
Nombreuses applications (simulations)
Frank Nielsen A1-22
Aujourd’hui l’ère du pétascale et demain celle de l’exascale
kiloFLOPS 103
megaFLOPS 106
gigaFLOPS 109
teraFLOPS 1012
petaFLOPS (PFLOPS, pétascale) 1015
exaFLOPS (EFLOPS, éxascale) 1018
zettaFLOPS 1021
yottaFLOPS 1024
... ...
googolFLOPS 10100
... mais pas uniquement la puissance de calcul pour les Super-Ordinateurs :
la mémoire (octets/bytes), la bande passante du réseau, etc.
Le futur : exaFlops (1018 vers 2017-2020), zetaFlops (1021) vers 2030 ?
Frank Nielsen A1-23
Mais pourquoi donc faire du HPC ? Être plus efficace !
◮ Aller plus vite et être plus précis ! (→ la météo)
◮ Résoudre de plus gros problèmes (→ simulation, → big data)
◮ Économiser de l’énergie ! À même puissance FLOPS utilisée, plus de
processeurs lents qui consomment moins !
◮ Simplifier des traitements de données : certains algorithmes sont
intrinséquement parallèles
vidéo/image : filtres foreach pixel/voxel, GPU & GPGPU
◮ Obtenir le résultat le plus rapidement possible en incluant le coût de
développement !
→ algorithmes parallèles plus faciles à implémenter qu’un code séquentiel
optimisé plus difficile à développer (par des ingénieurs). Avoir la solution
finale = implémenter un algorithme + exécuter cet algorithme.
Frank Nielsen A1-24
Le HPC en quelques images
Frank Nielsen A1-25
Cluster de machines (4 clusters en salles machines)
m´emoire
locale
processeur
m´emoire
locale
processeur
m´emoire
locale
processeur
m´emoire
locale
processeur
m´emoire
locale
processeur
m´emoire
locale
processeur
r´eseau
d’interconnexion
´echange de messages
avec MPI
Frank Nielsen A1-26
Topologie des réseaux d’interconnexion dans un cluster
Topologie (physique/virtuelle) importante pour le design des algorithmes
parallèles. → Abstraction
Comment faire une diffusion (broadcast) d’un nœud à tous les nœuds ?
Frank Nielsen A1-27
Évolution des processeurs
Des architectures mono-processeurs aux machines multi-cœurs
r´eseau
ordinateur
(CPU)
carte m`ere carte m`ere
CPU CPU
CPU CPU
cœur
un seul socketsocket socket
socketsocket
4 ordinateurs interconnect´es par un r´eseau une carte m`ere avec 4 processeurs un processeur quad-cœur
ordinateur
(CPU)
ordinateur
(CPU)
ordinateur
(CPU)
cœur
cœurcœur
Pour passer à l’échelle, dans le calcul haute performance, il faut utiliser un
cluster de machines
Frank Nielsen A1-28
Cluster moderne : machines hybrides/hétérogènes
r´eseau
d’interconnexion
(topologie)
nœud
Central Processing Unit
m´emoire
nœud
CPU CPU
CPUCPU
m´emoire
ordinateur simple
ordinateur quad processeurs
ordinateur moderne:
CPU multicœurs avec plusieurs cartes GPUs
node
cœur
m´emoire
GPU
GPU
C
P
U
Grappe d’ordinateurs
(computer cluster)
cœur
cœur cœur
Comment programmer ces clusters hybrides et hétérogènes ?
Frank Nielsen A1-29
Cadre théorique idéal différent de la pratique mais utile ...
◮ Tâche (job) : un programme à exécuter qui donne lieu à un processus
◮ Ordonnanceur : gestionnaire des ressources qui choisit l’affectation des
tâches (jobs) aux ressources du cluster (en salles info, SLURM)
◮ Cadre théorique pour ce cours lorsqu’on analyse un algorithme parallèle :
un processus P tourne sur son propre processeur (un CPU mono-cœur)
d’une machine qui constitue un nœud du cluster.
◮ En pratique : cluster hétérogène de machines (multi-cœurs, avec GPU).
Plusieurs processus peuvent se retrouver mappés par l’ordonnanceur sur le
même processeur (potentiellement sur le même cœur)
Frank Nielsen A1-30
HPC : granularité des calculs
granularité = proportion des calculs (grains = calculs locaux) sur les
communications (inter-processus).
≡ Fréquence des communications (ou synchronisation) entre les processus.
◮ grain fin (petit grain, fine-grained) : plein de petites tâches, données
souvent transferées entre les processus après de petits calculs (ex., GPU).
◮ gros grain (coarse-grained) : les données ne sont pas échangées souvent
et après des gros calculs. Cas extrême, embarrasingly parallel, très peu de
communications.
Frank Nielsen A1-31
Deux notions en calcule parallèle : parallélisme et
concurrence
Parallélisme et concurrence :
◮ Parallélisme : tâches exécutées litéralement en même temps,
(physiquement plusieurs unités de calcul)
◮ Concurrence : au moins deux tâches qui progressent conjointement dans le
temps. Pas nécessairement en même temps
(time-slicing sur un même CPU, multi-tâche sur un cœur)
Frank Nielsen A1-32
Modèles de programmation parallèle des nœuds
◮ Modèle de programmation vectorielle (SIMD, Cray)
◮ Modèle de programmation à mémoire distribuée :
échanges de messages explicites → MPI (ici = INF442 !)
◮ Modèle de programmation à mémoire partagée :
multi-threading (OpenMP), INF431
◮ Modèle de programmation hybride :
GPU, GPGPU pour certains calculs (CUDA, OpenCL, HMPP)
GPGPU = General Purpose GPU
◮ Modèle de programmation mixte :
Chaque processus MPI utilise plusieurs fils/threads (HPC geek !)
◮ Modèle de programmation mixte et hybride (MPI+fils+GPU, HPC
gourou !)
Frank Nielsen A1-33
Les Grandes Données, le Big Data ...
Traitement massif des données (HPC, gros grains), traitement des données
massives (HPC, petits grains). BigData = un buzzword très médiatisé,
renferme beaucoup de facettes, (large-scale)
Les 4 V sur les données :
◮ Volume
◮ Variété (hétérogène)
◮ Vitesse (données générées en temps réel, capteurs)
◮ Valeur (pas de simulation mais de la valorisation)
Frank Nielsen A1-34
Tolérance aux pannes : un problème récurrent sur clusters
Tolérance aux pannes des ordinateurs ?, des réseaux ?, des disques ?, etc. :
◮ MPI : zéro tolérance mais grande souplesse de programmation
◮ MapReduce (Hadoop) : grande tolérance mais modèle de calcul plus
limité
On peut faire du MapReduce (modèle de programmation //) avec MPI
Frank Nielsen A1-35
Quelques fausses idées sur les systèmes distribués !
1. Le réseau est fiable
2. Le temps de latence est nul
3. La bande passante est infinie
4. Le réseau est sûr
5. La topologie du réseau ne change pas
6. Il y a un et un seul administrateur réseau
7. Le coût de transport est nul
8. Le réseau est homogène
Frank Nielsen A1-36
Introduction à C++
memento C++ sur moodle
Frank Nielsen A1-37
Le langage Orienté Objet (OO) C++
◮ créé par Bjarne Stroustrup en 1983
◮ Orienté Objet (OO) avec typage statique.
à influencé Java et dérive de C (≈ 1970)
◮ Code compilé rapide (= Python interprété), pas de machines virtuelles
(= Java)
◮ On gère soi-même la mémoire : pas de ramasse miette (garbage
Collector, GC). Attention aux erreurs lors de l’exécution (system crash,
segmentation fault, core dump)
◮ Passage par valeurs, pointeurs ou références (=Java : passage par valeur
ou par référence pour les objets)
◮ Extensions de fichiers : .cc .cpp .cxx .c++ .h .hh .hpp .hxx .h++
◮ Utilise g++ (GNU Compiler Collection) de la fondation GNU
Frank Nielsen A1-38
Le compilateur C++ (GNU)
Standards (ANSI C++, C++11, etc.) et divers compilateurs
[france ~]$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2 -55)
Copyright (C) 2006 Free Software Foundation , Inc.
This is free software; see the source for copying
conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.
⇒ existe de nombreuses versions de g++ (C++98, C++11 ; etc.)STL
(Standard Template Librarry) par défaut dans C++98
Frank Nielsen A1-39
Bienvenue en C++
// pour les entrées et sorties :
#i n c l u d e <iostream >
i n t main ()
{
cout << " Bienvenue en INF442n" ;
r e t u r n 0; // pas obligatoire
}
g++ bienvenue.cpp -o bienvenue
bienvenue
cout = c(onsole) out
Frank Nielsen A1-40
Bienvenue au C++
#i n c l u d e <iostream >
// pour éviter décrire std : :cout
using namespace std ;
i n t promo=14;
i n t main ()
{
cout << " Bienvenue en INF442 X"<<promo<<endl ;
/∗ cout = Standard output stream
on  ’ e c r i t dans l e f l o t avec l e s chevrons <<
∗/
}
Frank Nielsen A1-41
Bienvenue au C++ : entrées et sorties
#i n c l u d e <iostream >
using namespace std ;
i n t main ()
{ i n t x ;
cout << " Entrez un e n t i e r : " ;
c i n >> x ;
cout << "son c a r r e e s t : "<<x∗x<<endl ;
}
Et aussi cerr qui ne temporise pas et affiche immédiatement les messages
importants (d’erreur) sur la console ...
Frank Nielsen A1-42
La mémoire vive : le ruban mémoire
i n t p=2014;
i n t ∗ ptrp = &p ; // un pointeur sur p
cout<<" a d r e s s e de l a case var p : "<<ptrp<<endl ;
(∗ ptrp ) = p+2; // on modifie le contenu de la case
cout<<p<<endl ;
0xffffcc04 = &p
2014 0xffffcc04
&ptrp (adressage)
contenu *ptrp (d´er´ef´erencement)
&p : adressage, l’adresse de p
∗p : déréférencement, on accède au contenu de p
(le contenu peut-être une adresse mémoire)
Frank Nielsen A1-43
Les pointeurs en C++ et le typage des variables
◮ Déclaration de pointeurs :
int * ptr_entier, *ptr1, *ptr2;
char * ptr_caractere;
double * ptr_real;
◮ Opérateur de référence (adressage) : &
int var=1;
int *var2; // pointeur sur une variable de type entier
var2=&var1; // var2 pointe sur var1 (alias)
◮ Opérateur de déréférencement : *
/* prend l’entier contenu dans l’endroit memoire
reference par var2 */
int var3=(*var2);
Frank Nielsen A1-44
C++ : les pointeurs en action !
i n c l u d e <iostream >
using namespace std ; // pour les Entrées/Sorties
i n t main ()
{
i n t var1 =442;
i n t ∗ var2 ;
var2=&var1 ; // var2 pointe sur var1
cout<<" v a l e u r de var2 : "<<var2<<endl ;
i n t var3 =(∗ var2 ) ;
cout<<" v a l e u r de var3 : "<<var3<<endl ;
r e t u r n 0; // fini sans le moindre probleme - :)
}
console> g++ programme.cpp -o monprogramme.exe
console> monprogramme.exe
Frank Nielsen A1-45
Pourquoi manipuler des pointeurs ?
Pointeur = variable qui sauvegarde la référence d’une autre variable.
Valeur d’un pointeur = adresse mémoire
i n t var1 =442; var2 = 2015;
i n t ∗ Ptr1 , ∗ Ptr2 ;
Ptr1 = &var1 ; Ptr2 = &var2 ;
Facilite l’implémentation de structures de données dynamiques
→ listes chaînées, arbres, graphes, etc.
En C++/C, les pointeurs permettent :
◮ d’allouer de la mémoire pour une variable en retournant un pointeur sur
cette zone
◮ d’accéder à la valeur de la variable par déréférencement : *Ptr1
◮ de libérer de la mémoire manuellement
* : opérateur de déréférence = “ valeur pointée par ”
Frank Nielsen A1-46
Les références et les alias
i n t val1 =442;
i n t val2 =2016;
// alias
i n t & r e f V a l 1=val1 ;
cout<< r e f V a l 1 <<endl ; //442
r e f V a l 1=val2 ;
// ci-dessous, le phénomène d’alias
cout<< val1 <<endl ; //2016
Frank Nielsen A1-47
Sémantiques différentes déclaration/code
La source de confusion (au début !) vient des sémantiques différentes
◮ Déclarations de variables :
◮ T* ptrVar : variable de type “pointeur sur type T” passée par
valeur=adresse mémoire
◮ T& refVar : variable de type T passée par référence
◮ T*& refPtrVar : variable de type “pointeur sur type T” passée par
référence
◮ Dans la partie instructions de code :
◮ &Var : retourne l’adresse utilisée pour stocker la valeur de Var
◮ *Var : si type de Var est “pointeur sur”, retourne la valeur stockée à
l’adresse contenue dans Var (valeur de Var)
Frank Nielsen A1-48
#i n c l u d e <iostream >
using namespace std ;
i n t main () {
i n t val1 = 2015 , val2 = 442;
i n t ∗ p1 , ∗ p2 ;
p1 = &val1 ; // p1 = adresse de val1
p2 = &val2 ; // p2 = adresse de val2
∗p1 = 2016; // valeur pointée par p1 = 2016
∗p2 = ∗p1 ; // valeur pointée par p2 = valeur pointée par p1
p1 = p2 ; // p1 = p2 (valeur du pointeur copiée)
∗p1 = 441; // valeur pointée par p1 = 441
cout << " val1=" << val1 << endl ; // affiche 2016
cout << " val2=" << val2 << endl ; // affiche 441
r e t u r n 0;
}
Frank Nielsen A1-49
int val1 = 2015, val2 = 442;
int * p1, * p2;
p1 = &val1; // p1 = adresse de val1
p2 = &val2; // p2 = adresse de val2
*p1 = 2016;
*p2 = *p1;
&val2&val1
2016 2016
p1 p2
Frank Nielsen A1-50
p1 = p2;
&val2&val1
2016 2016
p1 p2
Frank Nielsen A1-51
*p1 = 441;
&val2&val1
2016 441
p1 p2
Frank Nielsen A1-52
Les pointeurs de pointeurs
Rappel : Pointeur = variable qui a comme valeur la référence mémoire d’une
autre variable.
double a ;
double ∗ b ;
double ∗∗ c ;
double ∗∗∗ d ;
a =3.14159265;
b=&a ;
c=&b ;
d=&c ;
cout<<b<<’ n ’<<c<<endl<<d<<endl ;
Frank Nielsen A1-53
Les pointeurs de pointeurs
double a;
double* b;
double** c;
double*** d;
a=3.14;
b=&a;
c=&b;
d=&c;
a b c
3.14 0x22aac0
0x22aac0
0x22aab8
0x22aab8
0x22aab0
0x22aab0 &d
d
Frank Nielsen A1-54
Le pointeur NULL
NULL=0
◮ utile dans la construction récursive de structures de données (listes,
arbres, graphes, matrices creuses, etc.)
◮ ne pointe pas sur une référence valide or une adresse mémoire :
double * ptr=NULL;
... else return new Noeud("feuille", NULL, NULL);
◮ attention aux segmentation faults :
T ∗ ptr ; ptr=maFonctionSuper442 () ;
cout<< (∗T)<<endl ;
// peut exploser si T=NULL ici !
Frank Nielsen A1-55
Passage par valeurs et passage par références
void swap ( i n t& x , i n t& y ) // par référence
{ i n t temp = x ; x = y ; y = temp ;}
void swapPtr ( i n t ∗ Ptr1 , i n t ∗ Ptr2 ) // Attention !
{ i n t ∗ Ptr ; Ptr=Ptr1 ; Ptr1=Ptr2 ; Ptr2=Ptr ;}
void swapGoodPtr ( i n t ∗ x , i n t ∗ y ) // ok !
{ i n t temp = ∗x ; ∗x = ∗y ; ∗y = temp ;}
i n t main ()
{
i n t a = 2 , b = 3;
swap ( a , b ) ; cout<<a<<" "<<b<<endl ; // OK
a=2; b=3; i n t ∗ Ptra =&a ,∗ Ptrb =&b ;
swapPtr ( Ptra , Ptrb ) ;
cout<<∗Ptra<<" "<<∗Ptrb<<endl ; // non !
swapGoodPtr ( Ptra , Ptrb ) ;
cout<<∗Ptra<<" "<<∗Ptrb<<endl ; // oui !
Frank Nielsen A1-56
Pointeurs et références
◮ une référence est toujours définie, d’un type donné, et ne peux jamais
changer.
Pas d’arithmétique de références ni de coercion.
◮ en C++, passage par valeur ou par référence : Si la valeur est un
pointeur, la fonction pourra changer le contenu des cases mémoires
pointées, mais au retour de la fonction, les pointeurs arguments
restent inchangés.
◮ Passage par référence ne copie pas l’objet sur la pile d’appel des
fonctions :
i n t fonctionPassageParRef ( MaClasse& c l a s s e O b j e t )
{ . . . }
Frank Nielsen A1-57
Un mauvais exemple d’utilisation des références
dangling reference
i n t& v a r i a b l e L o c a l e ()
{ i n t x=442; r e t u r n x ;}
Ça compile avec un message d’alerte (warning) :
In f u n c t i o n i n t& v a r i a b l e L o c a l e () :
ptr12 . cpp : 5 : 6 : a t t e n t i o n : r e f e r e n c e to l o c a l v a r i a b l e
x returned [−Wreturn−l o c a l −addr ]
{ i n t x=442; r e t u r n x ;}
Pour transformer ces alertes en erreur de compilation, faire g++ -Werror man
g++ pour le manuel
Frank Nielsen A1-58
Exercice : la fonction magique !
#i n c l u d e <s t d i o . h>
i n t a = 23;
i n t fonctionMagique ( i n t b , i n t ∗p1 , i n t ∗p2 , i n t x ) {
i n t e ;
e = 14;
a = 15;
x = 16;
∗p1 = 17;
b = 18;
p2 = &b ;
∗p2 = 19;
r e t u r n b ;
}
i n t main () {
i n t b = 10 , c = 11 , d = 12 , e = 13 , f ;
f = fonctionMagique (b , &c , &d , a ) ;
p r i n t f ( "%d t%d t%d t%d t%d t%dn" , a , b , c , d , e , f ) ; //ici
syntaxe C
// 15 10 17 12 13 19
Frank Nielsen A1-59
Les tableaux en C++ : Allocation statique
Les indices commencent à 0 comme pour Java, mais on ne peut pas faire
tab.length !
int nombrePremiers [4] = { 2, 3, 5, 7 };
int baz [442] = { }; // valeurs initialisees a zero
int matrice [3][5]; // 3 lignes 5 colonnes
void procedure (int tableau[]) {}
Après, on verra la classe vector de la STL ...
Frank Nielsen A1-60
#i n c l u d e <iostream >
using namespace std ;
i n t main ()
{
i n t tab [ 5 ] ;
i n t ∗ p ;
p = tab ; ∗p = 10;
p++; ∗p = 20;
p = &tab [ 2 ] ; ∗p = 30;
// arithmétique de pointeurs !
p = tab + 3; ∗p = 40;
// arithmétique de pointeurs déréférencée !
p = tab ; ∗(p+4) = 50;
f o r ( i n t n=0; n<5; n++)
cout << tab [ n ] << " " ;
r e t u r n 0;} // 10 20 30 40 50
Frank Nielsen A1-61
Les pointeurs void
Syntaxe : void *ptrVoid
◮ un type spécial de pointeurs : pointe sur une zone mémoire non typée
◮ pratique car on peut pointer sur n’ importe quel type de variable (int,
int, char, string, T)
◮ ... mais on ne peut pas déférencer. Pour ce faire, on doit faire de la
coercion ( type casting ) : T* ptrT=(T *)ptrVoid;
double tabd [5]={1 ,2 ,3 ,4 ,5} , ∗ ptrd=tabd ;
cerr << ∗( tabd+3)<<endl ; // affiche 4
char ∗ ptrc2=(char ∗) tabd ;
void ∗ d= ( ptrc2+3∗ s i z e o f ( double ) ) ;
cerr <<(∗(double ∗) (d) )<<endl ; // // affiche 4
Frank Nielsen A1-62
Les tableaux : allocation dynamique en C++
On doit gérer l’espace mémoire soi-même en C++, et il faut donc
libérer la mémoire quand on ne l’utilise plus .
i n t t a i l l e =2015;
i n t ∗ tab ;
tab=new i n t [ t a i l l e ] ;
// ... utilisez ce tableau puis LIBERER le !
d e l e t e [ ] tab ;
Frank Nielsen A1-63
Pointeurs et tableaux
La valeur d’une variable tableau tab est l’adresse mémoire de son premier
élément
i n t tab [ 4 4 2 ] ;
i n t ∗ ptr ;
Le pointeur ptr est une variable qui stocke une adresse mémoire pour un int
(4 octets = 32 bits, sur architecture 32 bits). On peut donc faire :
ptr=tab ;
Un tableau est considéré comme un pointeur constant .
Il est donc interdit de faire :
tab=ptr ; // pas autorisé
Frank Nielsen A1-64
Allocation des tableaux multi-dimensionnels
#i n c l u d e <iostream >
using namespace std ;
i n t main ( i n t argc , char ∗ argv [ ] )
{
double ∗∗ m a t r i c e T r i a n g u l a i r e ;
i n t i , j , dimension =20;
m a t r i c e T r i a n g u l a i r e=new double ∗[ dimension ] ;
f o r ( i =0; i <dimension ; i++)
m a t r i c e T r i a n g u l a i r e [ i ]=new double [ dimension ] ;
f o r ( i =0; i <dimension ; i++)
f o r ( j =0; j<=i ; j++)
i f ( i==j ) m a t r i c e T r i a n g u l a i r e [ i ] [ j ]=1;
e l s e m a t r i c e T r i a n g u l a i r e [ i ] [ j ]=0;
Frank Nielsen A1-65
int d=2015;
double **T=new double*[d];
for(i=0;i<d;i++)
T[i]=new double[d];
T
T[0]
T[d-1]
T[1]
T[0][0]
T[1][0] T[1][1]
T[d − 1][0] T[d − 1][1] T[d − 1][d − 1]
pointeur sur un double* (type double**)
T[i] pointeur sur un double (type double*)
Frank Nielsen A1-66
Libérer la mémoire des tableaux (multi-dimensionnels) !
#i n c l u d e <iostream >
using namespace std ;
i n t main ( i n t argc , char ∗ argv [ ] )
{
double ∗∗ m a t r i c e T r i a n g u l a i r e ;
i n t i , j , dimension =20;
. . .
f o r ( i =0; i <dimension ; i++){
f o r ( j =0; j<=i ; j++)
{cout<<m a t r i c e T r i a n g u l a i r e [ i ] [ j ]<<" " ;}
cout<<endl ;
}
. . .
Frank Nielsen A1-67
Les dangers des pointeurs : dangling pointer
Un pointeur qui ne pointe sur rien : dangling pointer
i n t main ()
{ i n t ∗ arrayPtr1 ;
i n t ∗ arrayPtr2 = new i n t [ 4 4 2 ] ;
arrayPtr1 = arrayPtr2 ;
d e l e t e [ ] arrayPtr2 ;
// si on a de la chance quelque chose sinon
// une segmentation fault, dépend du tas
cout << arrayPtr1 [ 4 4 1 ] ;
r e t u r n 0;}
Nombreux effets de bords imprévisibles possibles : dépend de l’historique de
l’utilisation du tas (heap)
Frank Nielsen A1-68
Les dangers des pointeurs : zones non-accessibles
On peut réserver des zones mémoires qui ne seront plus accessibles :
i n t ∗ Ptr1= 2015;
i n t ∗ Ptr2 = 442;
Ptr1 = Ptr2 ;
Imaginez maintenant :
i n t ∗ Ptr1= new i n t [ 2 0 1 5 ] ;
i n t ∗ Ptr2 = 442;
Ptr1 = Ptr2 ;
out of memory !
Outil de visualisation dynamique et de suivi de la mémoire lors de l’exécution
de programmes. http://valgrind.org/
Frank Nielsen A1-69
Objets et méthodes en C++
Attention, il faut mettre un ; après la déclaration de classe (= Java)
c l a s s Boite
{ p u b l i c :
double h o r i z o n t a l ; // dimension largeur
double v e r t i c a l ; /∗ dimension hauteur ∗/
};
i n t main ( )
{ Boite B1 , B2 ;
double s u r f a c e = 0 . 0 ;
B1 . h o r i z o n t a l = 5 . 0 ; B1 . v e r t i c a l = 6 . 0 ;
s u r f a c e = B1 . h o r i z o n t a l ∗ B1 . v e r t i c a l ;
cout << " Surface de l a b o i t e B1 : " << s u r f a c e <<
endl ;
r e t u r n 0;}
Frank Nielsen A1-70
Objets : constructeur(s) et destructeur ˜ en C++
Il peut y avoir plusieurs constructeurs mais toujours un seul destructeur.
c l a s s Donnee
{ p u b l i c :
i n t d ;
double ∗ a t t r i b u t ;
// constructeurs (plusieurs possibles)
Donnee () {d=3; a t t r i b u t=new double [ d ] ; }
Donnee ( i n t dd ) {d=dd ; a t t r i b u t=new double [ d ] ; }
// destructeur : un seul
~Donnee () { d e l e t e [ ] a t t r i b u t ; cout<<" Destructeur
appele "<<endl ;}
};
i n t main ()
{ i n t dim=500; Donnee ∗x=new Donnee ( dim ) ; d e l e t e x ;
r e t u r n 0;}
Frank Nielsen A1-71
Hiérarchies de classes
Utile lorsqu’on manipule des hiérarchies de classes,
polymorphisme dynamique .
double rand442 () { r e t u r n ( double ) rand () / RAND_MAX;}
c l a s s Polygon { p u b l i c : i n t n ; s t r i n g name ; } ;
c l a s s T r i a n g l e : p u b l i c Polygon { p u b l i c : T r i a n g l e () {n=3;
name=" t r i a n g l e " ; } } ;
c l a s s Carre : p u b l i c Polygon { p u b l i c : Carre () {n=4;name="
c a r r e " ; } } ;
i n t main ()
{
Polygon ∗ ptr ;
srand ( time (NULL) ) ;
i f ( rand442 () <0.5) ptr=new Carre () ;
e l s e ptr=new T r i a n g l e () ;
cout<<" cotes ="<< ptr−>n ;
r e t u r n 0;}
Frank Nielsen A1-72
C++ : La surcharge d’opérateurs (overloading operators)
Il est pratique de redéfinir certains opérateurs (comme +, /, =, etc.) en les
surchargeant . Par exemple, redéfinir l’égalité pour un objet en recopiant tous
les enregistrements (champs).
c l a s s Complex
{
p u b l i c :
Complex ( double re , double im ) : r e a l ( re ) , imag ( im )
{};
Complex operator +(const Complex& other ) ;
Complex operator =(const Complex& other ) ;
p r i v a t e :
double real , imag ; } ;
Complex Complex : : operator +(const Complex& other )
{
double r e s u l t _ r e a l = r e a l + other . r e a l ;
double result_imaginary = imag + other . imag ;
r e t u r n Complex ( r e s u l t _ r e a l , result_imaginary ) ;}
Frank Nielsen A1-73
f r i e n d ostream &operator <<(ostream &out , Complex c )
//output
{
out<<" r e a l part : "<<c . real <<"n" ;
out<<"imag part : "<<c . imag<<"n" ;
r e t u r n out ;
}
f r i e n d istream &operator >>(istream &in , Complex &c )
//input
{
cout<<" enter r e a l part : n" ;
in>>c . r e a l ;
cout<<" enter imag part : n" ;
in>>c . imag ;
r e t u r n in ;
}
Complex a ( 2 . 1 , 3 . 2 ) , b ( 5 . 3 , 6 . 4 ) ;
cout<<a<<b ;
Frank Nielsen A1-74
La généricité en C++ : les templates
template <class T> void swap ( T& a, T& b )
{T c(a); a=b; b=c;}
◮ Notez que la classe T doit avoir un constructeur T(Tobject).
◮ Il faudra surcharger l’opérateur =
Frank Nielsen A1-75
La classe vector de la STL
STL = Standard Template Library :
formalisme hautement générique, container, iterator
Container qui permet de gérer des tableaux de taille dynamique aisément.
#i n c l u d e <vector >
i n t s i z e = 442;
// initialisation à 0
std : : vector <int > ar ra y ( s i z e ) ;
// on peut rajouter dynamiquement des élèments
f o r ( i n t i =0; i <2∗ s i z e ; ++i )
{ a rr ay [ i ] = i ;}
// pas besoin de delete
http://www.cplusplus.com/reference/vector/vector/
http://www.cplusplus.com/reference/cstring/size_t/
Frank Nielsen A1-76
Le mot clé const dans les méthodes
const indique que l’on ne peut pas changer les variables de l’objet this
c l a s s MaClasse{
i n t compteur =0;
void Proc1 ()
{
compteur++; // ça marche
std : : cout << " Incremente " << std : : endl ;
}
void Proc2 () const
{// cela ne compilera pas car on veut changer counter !
compteur++;
std : : cout << " Incremente " << std : : endl ;
}
};
Frank Nielsen A1-77
Quizz C++
void proc ()
{
i n t ∗ tab ;
tab=new i n t [ 2 0 1 4 ] ;
// ...
}
Lors d’un appel à proc, le tableau tab est créé en mémoire :
1. dans la pile d’exécution
2. dans le tas
Frank Nielsen A1-78
Quizz C++
void proc ()
{
i n t tab [ 2 0 1 4 ] ;
// ...
}
Lors d’un appel à proc, le tableau tab est créé en mémoire :
1. dans la pile d’exécution
2. dans le tas
Frank Nielsen A1-79
Quizz C++
bool p a i r e ( i n t x )
{
i f ( x=0) { r e t u r n true ;}
e l s e { r e t u r n ! p a i r e ( x−1) ;}
}
i n t main ()
{ p a i r e (5) ;}
Que se passe t’il lorsqu’on appelle la fonction récursive paire(5) :
1. le programme retourne false
2. le programme retourne true
3. on obtient un message d’erreur Segmentation fault (core dumped)
Frank Nielsen A1-80
Quizz C++
c l a s s Tab{
p u b l i c : i n t n ;
i n t ∗ e l ;
Tab( i n t nb ) {n=nb ; e l=new i n t [ n ] ; }
~Tab () { cerr <<"T" ; i f ( e l != 0 ) d e l e t e [ ] e l ;}
};
Tab∗ func ()
{ Tab∗ T1=new Tab (5) ; }
i n t main () {Tab ∗ t=func () ; r e t u r n 0; }
Est-ce que le programme est correct ?
1. non
2. oui
3. oui, mais le tableau n’a pas été libéré : il manque delete t;
Frank Nielsen A1-81
Quizz C++
c l a s s Test {
i n t value ;
p u b l i c :
Test ( i n t v = 0) { value = v ;}
i n t getValue () const { r e t u r n value ;}
i n t incGetValue () const { value++; r e t u r n value ;}
};
i n t main () {
Test t (20) ;
std : : cout<<t . getValue ()<<std : : endl ;
r e t u r n 0;}
Est-ce que le programme se termine normalement ?
1. oui
2. non
3. le programme ne compile pas
Frank Nielsen A1-82
Quizz C++
#i n c l u d e <iostream >
i n t main ()
{
double a =0.00001 , b=88888, c ;
c = ( ( a+b) ∗( a+b) − 2∗a∗b − b∗b ) / ( a∗a ) ;
// mathématiquement, que vaut c ?
std : : cout << c << std : : endl ;
}
Quelle est la valeur de c retourné par le programme ?
1. 1
2. une autre valeur (par exemple, 9536.74)
3. le programme ne compile pas !
Frank Nielsen A1-83
TD 1 : Les fondamentaux du C++
Rien ne remplace l’expérience en programmation ...
◮ Quizz (5-15 minutes)
◮ Quelques commandes Unix
◮ Hello world !
◮ Débugger un programme
◮ Echange par références
◮ Echange par pointeurs
◮ Transposition de matrices
◮ Multiplication de matrices
Inscrivez vous au tutorat si vous en ressentez le besoin !
Frank Nielsen A1-84
Entraînement au TD1
Petits exercices pour se préparer au TD de cet après-midi :
◮ créer une matrice diagonale
◮ imprimer sur la console une matrice
◮ créer une matrice symétrique
Frank Nielsen A1-85
#i n c l u d e <iostream >
using namespace std ;
// on ne connait pas la longueur de diag
// donc on doit passer sa longueur en argument
double ∗∗ diagMat ( i n t dim , double ∗ diag )
{
i n t i , j ;
double ∗∗ r e s ;
r e s=new double ∗ [ dim ] ;
f o r ( i =0; i <dim ; i++)
{ r e s [ i ]=new double [ dim ] ; }
f o r ( i =0; i <dim ; i++)
{ f o r ( j =0; j<dim ; j++)
{ i f ( i==j ) r e s [ i ] [ i ]= diag [ i ] ;
e l s e r e s [ i ] [ j ]=0;}
}
r e t u r n r e s ;}
Frank Nielsen A1-86
Procédure = fonction qui ne retourne rient (void)
void printMat ( double ∗∗M, i n t dim )
{ i n t i , j ;
f o r ( i =0; i <dim ; i++)
{ f o r ( j =0; j<dim ; j++)
{cout<<M[ i ] [ j ]<<" t " ;}
cout<<endl ;
}
}
i n t main ()
{
double diag [3]={1 ,2 ,3};
double ∗∗ Mdiag ;
Mdiag=diagMat (3 , diag ) ; printMat ( Mdiag , 3 ) ;
r e t u r n 0;
}
Frank Nielsen A1-87
Version plus ’geek’, déconseillée, mais qu’on retrouve dans des codes ...
← issus de la syntaxe C
double ∗∗ diagMat ( i n t dim , double ∗ diag )
{
i n t i , j ;
double ∗∗ r e s ;
// par default, les valeurs sont egales a zero
r e s=new double ∗ [ dim ] ;
f o r ( i =0; i <dim ; i++)
r e s [ i ]=new double [ dim ] ;
f o r ( i =0; i <dim ; i++)
f o r ( j =0; j<dim ; j++)
r e s [ i ] [ j ]=( ( i==j ) ? diag [ i ] : 0) ;
r e t u r n r e s ;
}
Frank Nielsen A1-88
#i n c l u d e <iostream >
// pour drand48(), inclure
#i n c l u d e <s t d l i b . h>
using namespace std ;
double ∗∗ symMat( i n t dim )
{ i n t i , j ;
double ∗∗ r e s ;
r e s=new double ∗ [ dim ] ;
f o r ( i =0; i <dim ; i++) r e s [ i ]=new double [ dim ] ;
f o r ( i =0; i <dim ; i++)
f o r ( j =0; j<=i ; j++)
{ r e s [ i ] [ j ]=drand48 () ; r e s [ j ] [ i ]= r e s [ i ] [ j ] ; }
r e t u r n r e s ;
}
Frank Nielsen A1-89
Déconseillé mais on peut réécrire ce code comme suit :
double ∗∗ symMat( i n t dim )
{ i n t i , j ;
double ∗∗ r e s ;
r e s=new double ∗ [ dim ] ;
f o r ( i =0; i <dim ; i++) r e s [ i ]=new double [ dim ] ;
f o r ( i =0; i <dim ; i++)
f o r ( j =0; j<=i ; j++)
{ r e s [ i ] [ j ]= r e s [ j ] [ i ]=drand48 () ;
// avant : res[i][j]=drand48() ;res[j][i]=res[i][j] ;
}
r e t u r n r e s ;
}
Frank Nielsen A1-90
Petite introduction à Unix
Frank Nielsen A1-91
UNIX
Unix est un système d’exploitation développé dans les années 1970 dans les
laboratoires Bell Labs d’ AT&T par Ken Thompson et Dennis Ritchie.
Frank Nielsen A1-92
Commandes shell (Unix)
◮ Ouvrir une fenêtre shell (en salles machines, shell = bash)
◮ Lit le fichier de configuration initiale (= votre fichier .bashrc) dans
votre répertoire “home” (˜).
more .bashrc
Modifier en utilisant un éditeur de texte (ou vi, emacs, ...)
Puis relire la configuration à n’importe quel instant d’une session avec :
source .bashrc
Frank Nielsen A1-93
Exemple de fichier .bashrc
Pour les curieux :
i f [ −f / e t c / b a s h r c ] ; then
. / e t c / b a s h r c
f i
# Prompt
PS1=" [  h W] $ "
a l i a s rm=’rm −i ’
a l i a s cp=’cp −i ’
a l i a s mv=’mv −i ’
a l i a s mm=’/ u s r / l o c a l /openmpi −1.8.3/ b i n / mpic++ −I / u s r / l o c a l / boost −1.56.0/ i n c l u d e /
−L/ u s r / l o c a l / boost −1.56.0/ l i b / −lboost_mpi −l b o o s t _ s e r i a l i z a t i o n ’
e x p o r t PATH=/u s r / l i b / openmpi /1.4− gcc / b i n : ${PATH}
e x p o r t PATH=/u s r / l o c a l / boost −1.39.0/ i n c l u d e / boost −1_39 : ${PATH}
LS_COLORS=’ d i =0;35 ’ ; e x p o r t LS_COLORS
e x p o r t LD_LIBRARY_PATH=$LD_LIBRARY_PATH: / u s r / l o c a l /openmpi −1.8.3/ l i b / : / u s r / l o c a l
/ boost −1.56.0/ l i b /
Frank Nielsen A1-94
Quelques rudiments d’Unix
◮ Qui suis-je ? id
[ f r a n c e ~] $ i d
u i d =11234( f r a n k . n i e l s e n ) g i d =11000( p r o f s ) groups =11000( p r o f s )
◮ Lister, renommer et effacer des fichiers : ls, mv (move) et rm (remove,
option -i par défaut)
◮ Créer un fichier ou toucher à sa date : touch
◮ Visualiser et concatener des fichiers : more et cat
more fichier
Frank Nielsen A1-95
Rudiments d’Unix
Les Entrées/Sorties (E/Ss) et le pipe |
[france ~]$ cat fichier1.cpp fichier2.cpp |wc
26 68 591
Manuel :
[france ~]$ man wc
Redirections :
programme <input >output 2>error.log
Frank Nielsen A1-96
Rudiments d’Unix : les tâches (jobs)
◮ Lister les processus courants (leurs numéros, pid) : ps
(avec options comme ps -a)
◮ Suspendre un processus avec Control-Z (Ctrl)
sleep 10000
Ctrl-Z
◮ Place une tâche suspendue en processus de fond :
bg
◮ Tuer des processus ou envoyer des signaux aux pids : kill
[france ~]$ sleep 5000 &
[1] 13728
[france ~]$ kill %1
[1]+ Terminated sleep 5000
Frank Nielsen A1-97
Résumé
◮ le HPC sert à être plus efficace :
plus vite, plus fines simulations, plus grandes données, etc.
On peut simuler un ordinateur paralléle sur une machine séquentielle mais
bien plus lent !
◮ le C++ est un langage objet compilé, construit sur le langage C
◮ Unix est un système d’exploitation multi-tâches, ré-écrit en C
Frank Nielsen A1-98
Résumé des notions de C++
◮ comprendre la mémoire locale (pile) et la mémoire globale (tas)
◮ passage par valeur, référence ou passage par pointeur des arguments
◮ allocation dynamique (new) et gestion manuelle de la mémoire (delete)
◮ classe et surcharge des opérateurs
Frank Nielsen A1-99
Résumé sur les pointeurs et références
& : opérateur de référence = “ adresse de ”
* : opérateur de déréférence = “ valeur pointée par ”
◮ pointeurs : les valeurs = adresses mémoires. Sauvegarde une référence sur
une autre variable.
◮ pointeurs et tableaux (→ pointeurs constants), pointeurs de pointeurs, ...
◮ pointeurs void pointe sur n’importe quel type mais ne peut-être
déréférencée (→ coercion, type casting)
◮ pointeurs NULL
◮ pointeurs et mémoire du tas : dangling pointers (mémoire désallouée →
segmentation fault), plus accessible (garbage)
◮ références : utile pour le passage d’arguments aux fonctions. Pas
d’arithmétique de références, de casting. Une référence ne change jamais
et ne peut être NULL
Frank Nielsen A1-100
Sur le web ...
https://www.lix.polytechnique.fr/~nielsen/HPC4DS/
Frank Nielsen A1-101
INF442 : Traitement des Données Massives
A2 : Le regroupement hiérarchique
suivi d’une
introduction à C++ STL
Frank Nielsen
nielsen@lix.polytechnique.fr
X2014
13 avril 2016
Frank Nielsen A1-1
Science des données : le clustering/regroupement
Vision duale du cluster :
◮ Grouper en paquets (=clusters) homogènes les données
◮ Séparer les données en paquets distincts
Frank Nielsen A1-3
Le clustering/regroupement
◮ clusters linéairement séparables
◮ ou pas : → méthode à noyaux qui permet toujours de supposer la
séparabilité linéaire en augmentant la dimension
Frank Nielsen A1-4
Clustering plat et clustering hiérarchique
clustering plat clustering hiérarchique
k-moyennes diagramme de Venn
Frank Nielsen A1-5
Le clustering : données en dimension > 3
Soupe de données, combien de catégories (= clusters) ?
Comment visualiser les données de grandes dimensions (cartes SOMs, SNE)
Frank Nielsen A1-6
Le clustering hiérarchique ascendant
On part des données X = {x1, ..., xn} qui sont des feuilles et on fusionne
récursivement au fur et à mesure les sous-arbres jusqu’à ne plus qu’avoir un
seul arbre.
ascendant (feuilles → arbre) vs. descendant (arbre → feuilles)
Frank Nielsen A1-7
Le clustering hiérarchique ascendant (Vis. 2D)
Frank Nielsen A1-8
Le clustering hiérarchique ascendant (Iris 4D)
Frank Nielsen A1-9
Le clustering hiérarchique ascendant
Plusieurs critères pour la fusion de deux sous-arbres dont les sous-ensembles
de données Gi et Gj sont stockées dans leurs feuilles :
◮ stratégie du saut minimum : Single Linkage (SL)
∆(Xi , Xj ) = min
xi ∈Xi ,xj ∈Xj
D(xi , xj )
◮ stratégie du saut maximum (ou diamètre) : Complete Linkage (CL)
∆(Xi , Xj ) = max
xi ∈Xi ,xj ∈Xj
D(xi , xj )
◮ stratégie du saut moyen : Group Average (GA)
∆(Xi , Xj ) =
1
|Xi ||Xj |
xi ∈Xi xj ∈Xj
D(xi , xj )
Les feuilles initiales forment une forêt d’arbres à une feuille, puis on fait du
chainage d’arbres en exactement n − 1 étapes...
Hierarchical Cluster Analysis (HCA) : regroupement hiérarchique
Frank Nielsen A1-10
Les différents sauts illustrés
Single Linkage
SL (minimum distance)
Complete Linkage
CL, diameter
Group Average
GA, mean distance
Frank Nielsen A1-11
Le clustering hiérarchique
I N F 4 4 2
I, N 4, 4
I, N, F 4, 4, 2
I,N,F,4,4,2
feuilles
nœuds internes
hauteur:
nombre de fusions
0
1
2
3
Frank Nielsen A1-12
Distance élémentaire entre deux données
∆(·, ·) (groupes) et D(·, ·) (éléments)
◮ Distance Euclidienne : DE (p, q) = d
i=1(pi − qi )2)
◮ Distance de Manhattan (city block, L1) : D1(p, q) = d
i=1 |pi − qi |
◮ Distance induite par une norme quelconque · :
D(p, q) = p − q .
Distance Lp :
Dp(p, q) =
d
i=1
|pi − qi |p
1
p
◮ Distance de Mahalanobis :
DΣ(p, q) = (p − q)⊤Σ−1(p − q) = DE (L⊤
p, L⊤
q),
Σ−1 = L⊤L (décomposition de Cholesky). Σ est la matrice de covariance
et Σ−1 la matrice de précision.
Frank Nielsen A1-13
Le clustering par agglomération
◮ Initialiser xi dans un cluster singleton Gi = {xi }
◮ Tant qu’il reste au moins deux clusters :
◮ Choisir Gi et Gj tel que ∆(Gi , Gj ) soit minimal
◮ Fusionner Gi,j = Gi ∪ Gj (ajouter Gi,j et retirer Gi et Gj )
⇒ Exactement n − 1 étapes de fusion
⇒ Le résultat d’un regroupement hiérarchique est un dendrogramme.
Différent d’un algorithme de partitionnement (clustering plat) comme les
k-moyennes.
Frank Nielsen A1-14
Frank Nielsen A1-15
Dendrogrammes et arbres philogénétiques
Théorie de l’évolution
→ horloge
Frank Nielsen A1-16
Critère de fusion de Ward
On fait intervenir les centroïdes des groupes ( = centre de masse) pour
implanter un critère qui minimise la somme des variances des clusters.
c(X′) est le centroïde du sous-ensemble X′ : c(X′) = 1
|X′| x∈X′ x
Critère de Ward pour fusionner Gi (ni = |Gi |) avec Gj (nj = |Gj |) :
∆(Gi , Gj ) =
ni nj
ni + nj
c(Gi ) − c(Gj ) 2
(di,j = xi − xj
2)
→ Très utilisé en pratique
Frank Nielsen A1-17
Critère de Ward et inversion
◮ similarité entre deux groupes S(Xi , Xj ) comme S(Xi , Xj ) = −∆(Xi , Xj )
◮ opération de fusion est monotone si pour une séquence de fusion (chemin
du dendrogramme) on a S1 ≥ S2 ≥ ... ≥ Sl .
x3x2x1
S({x1, x2}, {x3})
x1
x2
x3
S({x1}, {x2})
→ Inversion potentielle pour Ward, mais jamais pour les sauts
minimum/moyen/maximum
Variance S(X) = 1
n i (xi − ¯x)
Frank Nielsen A1-18
Dendrogramme : obtenir des partitions
Deux coupes différentes donnent lieu à deux clusterings plats différents
(partitions)
Frank Nielsen A1-19
Distances : métriques et ultramétriques
Une distance d(·, ·) est :
◮ métrique si elle satisfait les trois axiomes :
◮ d(x, y) ≥ 0 avec égalité pour x = y seulement
◮ d(x, y) = d(y, x) symétrie
◮ d(x, y) ≤ d(x, z) + d(z, y), inégalité triangulaire
◮ ultramétrique si elle satisfait les axiomes :
◮ d(x, y) ≥ 0 avec égalité pour x = y seulement
◮ d(x, y) = d(y, x) symétrie
◮ d(x, y) ≤ max(d(x, z), d(z, y))
Frank Nielsen A1-20
Distance et évolution
Dans les arbres phylogénétiques, la distance entre deux espèces impose des
restrictions sur la fonction distance :
◮ Arbre additif (additive tree) : poids sur chaque arête tel que pour chaque
paire de feuilles, la distance est la somme des distances des arêtes les
reliant.
◮ Arbre ultramétrique : Distances entre deux feuilles i et j et
leur ancêtre commun k sont égales : di,k = dj,k.
◮ permet de définir une horloge globale : 1
2 di,j (hauteur) correspond au
temps écoulé,
Frank Nielsen A1-21
Dendrogrammes et arbres philogénétiques
horloge biologique, arbre ultramétrique
Frank Nielsen A1-22
Regroupement hiérarchique par l’algorithme UPGMA
◮ UPGMA : Unweighted Pair Group Method using arithmetic Averages
◮ Clustering avec saut moyen (= Average Linkage, AL)
D(Gi , Gj ) =
1
ni nj
xi ∈Gi xj ∈Gj
d(xi , xj )
◮ Si les données X sont accompagnées d’une matrice carrée des distances
M = [Di,j ]i,j avec Di,j = D(xi , xj ) qui satisfait les propriétés
ultramétriques, alors il existe un unique arbre ultramétrique qui peut
être construit par l’algorithme UPGMA.
Frank Nielsen A1-23
Regroupement hiérarchique par UPGMA (résumé)
◮ Initialise xi a son cluster Ci et le positionne à hauteur 0.
◮ Tant qu’il reste plus de deux clusters :
◮ Trouver les clusters Ci et Cj qui ont la distance di,j minimale
◮ Définir un nouveau cluster Ck = Ci ∪ Cj et calculer la distance dk,l pour
tout l
◮ Ajouter un nœud k avec les fils Ci et Cj et positionner le à hauteur 1
2 di,j
◮ Retirer Ci et Cj de la liste des clusters, et continuer jusqu’à temps d’obtenir
la racine.
◮ Pour les deux derniers clusters Ci , and Cj , placer la racine à hauteur
1
2 D(Ci , Cj ).
Frank Nielsen A1-24
Les arbres : Rappel sur une implantation en Java
Structure récursive (en C++, on utilise les pointeurs !)
class BinaryTree <E>
{
E node;
BinaryTree left ,right;
BinaryTree(E v)
{left=right=null; node=v;}
BinaryTree(E v, BinaryTree l, BinaryTree r)
{node=v; left=l;right=r;}
}
...
BinaryTree BT;
BT=new BinaryTree (442 , new BinaryTree (421 , new BinaryTree (311 ,
null ,new BinaryTree (321)),new BinaryTree (431)),new
BinaryTree (411)) ;
...
Frank Nielsen A1-25
Implantation en Java
class BinaryTree <E>
{
...
String serialize (){String lefts ,rights;
if (left == null) lefts="nil"; else lefts=left.serialize ();
if (right == null) rights="nil"; else rights=right.serialize ();
return "(node="+node+"("+lefts+","+rights+")";
}
}
...
System.out.println(BT.serialize ());
...
On ne gére pas la désallocation mémoire ... (en C++, on doit faire des delete
Voyons voir en C++ comment implémenter ces structures de données grâce
aux pointeurs !
Frank Nielsen A1-26
Listes chaînées et arbres en
C++
Frank Nielsen A1-27
Dans le fichier IntList.h
c l a s s I n t L i s t {
p u b l i c :
I n t L i s t ( i n t i , I n t L i s t ∗ next ) ; // constructeur
~ I n t L i s t () ; // destructeur
void p r i n t () ;
void p r i n t ( i n t t h r e s h o l d ) ; // elements > threshold
I n t L i s t ∗ s u b L i s t ( i n t t h r e s h o l d ) ; // sous-liste elements >
threshold
p r i v a t e : // la cellule
i n t i ;
I n t L i s t ∗ next ;
};
Frank Nielsen A1-28
Dans le fichier IntList.cpp
#i n c l u d e " I n t L i s t . h"
#i n c l u d e <iostream >
I n t L i s t : : I n t L i s t ( i n t i , I n t L i s t ∗ next ) {
t h i s −>i = i ;
t h i s −>next = next ;
}
I n t L i s t : : ~ I n t L i s t () {}
void I n t L i s t : : p r i n t () {
std : : cout << i << std : : endl ;
i f ( next ) next−>p r i n t () ;
}
Frank Nielsen A1-29
Dans le fichier IntList.cpp
void I n t L i s t : : p r i n t ( i n t t h r e s h o l d ) {
i f ( i >t h r e s h o l d ) std : : cout << i << std : : endl ;
i f ( next ) next−>p r i n t ( t h r e s h o l d ) ;
}
I n t L i s t ∗ I n t L i s t : : s u b L i s t ( i n t t h r e s h o l d ) {
I n t L i s t ∗ nextSubList = 0;
i f ( next ) nextSubList = next−>s u b L i s t ( t h r e s h o l d ) ;
i f ( i > t h r e s h o l d ) r e t u r n new I n t L i s t ( i ,
nextSubList ) ;
r e t u r n nextSubList ;
}
Frank Nielsen A1-30
#i n c l u d e " I n t L i s t . h"
#i n c l u d e <iostream >
i n t main () {
I n t L i s t ∗ l i s t = new I n t L i s t (2 , new I n t L i s t (17 , new
I n t L i s t (8 , new I n t L i s t (75 , new I n t L i s t (92 , 0) ) )
) ) ;
l i s t −>p r i n t () ;
std : : cout << std : : endl ;
Frank Nielsen A1-31
#i n c l u d e " I n t L i s t . h"
#i n c l u d e <iostream >
i n t main () {
I n t L i s t ∗ l i s t = new I n t L i s t (2 , new I n t L i s t (17 , new
I n t L i s t (8 , new I n t L i s t (75 , new I n t L i s t (92 , 0) ) )
) ) ;
l i s t −>p r i n t () ;
std : : cout << std : : endl ;
Frank Nielsen A1-32
Structure récursive d’arbres en C++
Dans le fichier tree.h (ou encore tree.hpp avec pp=++)
c l a s s Tree {
i n t key ; // The key
Tree ∗ l e f t , ∗ r i g h t ; // The two subtrees (pointers !)
p u b l i c :
Tree ( i n t k , Tree ∗ l , Tree ∗ r ) ;
~Tree () ;
// somme des entiers stockés aux nœuds
i n t sumt () ;
};
Frank Nielsen A1-33
Dans le fichier tree.cpp
Tree : : ~ Tree () { cerr <<" . "<<endl ;
i f ( l e f t ) d e l e t e l e f t ;
i f ( r i g h t ) d e l e t e r i g h t ;
}
Tree : : Tree ( i n t k , Tree ∗ l , Tree ∗ r )
{ key=k ; l e f t=l ; r i g h t=r ;}
i n t Tree : : sumt ()
{ i n t r e s=key ;
i f ( l e f t ) r e s+=l e f t −>sumt () ;
i f ( r i g h t ) r e s+=right −>sumt () ;
r e t u r n r e s ;}
Frank Nielsen A1-34
Dans le fichier main.cpp
#i n c l u d e <iostream >
#i n c l u d e " t r e e . h"
using namespace std ;
i n t main ( i n t argc , char ∗∗ argv ) {
Tree ∗ l =new Tree (3 ,NULL,NULL) ;
Tree ∗ r =new Tree (2 ,NULL,NULL) ;
Tree ∗ r a c i n e = new Tree (6 , l , r ) ;
cout << racine −>sumt () ;
d e l e t e r a c i n e ;
r e t u r n 0;
On trouve 11 et trois petits points affichés sur la console
Frank Nielsen A1-35
La bibliothèque
C++ STL :
généricité
Frank Nielsen A1-36
Les classes génériques en C++
But de la généricité = produire du code indépendant des types (instanciés
lors de l’usage) :
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
i n t compare ( const i n t &value1 , const i n t &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1;
r e t u r n 0;
}
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
i n t compare ( const s t r i n g &value1 , const s t r i n g &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1;
r e t u r n 0;}
⇒ factorisation du code puis à la compilation, code polymorphique pour les
divers types requis : génération des codes spécifiques pour les types demandés.
Frank Nielsen A1-37
#i n c l u d e <iostream >
#i n c l u d e <s t r i n g >
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
template <c l a s s T>
i n t compare ( const T &value1 , const T &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1;
r e t u r n 0;
}
// On est gentil ici pour le compilateur :
// on indique explicitement les types demandés
i n t main ( i n t argc , char ∗∗ argv ) {
std : : s t r i n g h( " h e l l o " ) , w( " world " ) ;
std : : cout << compare<std : : s t r i n g >(h , w) << std : : endl ;
std : : cout << compare<int >(10 , 20) << std : : endl ;
std : : cout << compare<double >(50.5 , 50.6) << std : : endl ;
r e t u r n 0;}
Frank Nielsen A1-38
Inférence des types demandés par le compilateur
#i n c l u d e <iostream >
#i n c l u d e <s t r i n g >
// returns 0 if equal, 1 if value1 is bigger, -1 otherwise
template <c l a s s T>
i n t compare ( const T &value1 , const T &value2 ) {
i f ( value1 < value2 ) r e t u r n −1;
i f ( value2 < value1 ) r e t u r n 1;
r e t u r n 0;
}
// Le compilateur doit trouver le type demande ici :
// inférence de types
i n t main ( i n t argc , char ∗∗ argv ) {
std : : s t r i n g h( " h e l l o " ) , w( " world " ) ;
std : : cout << compare (h , w) << std : : endl ;
std : : cout << compare (10 , 20) << std : : endl ;
std : : cout << compare (50.5 , 50.6) << std : : endl ;
r e t u r n 0;}
Frank Nielsen A1-39
Mécanisme de compilation et templates
◮ le compilateur ne génére pas de code directement lorsqu’il rencontre une
classe/fonction template parce qu’il ne connaît pas encore quelles seront
les types demandés.
◮ quand le compilateur rencontre une fonction template utilisée, il sait quel
type est demandé : Il instancie alors le template et compile le code
correspondant
⇒ les classes/fonctions templates doivent donc se trouver dans le fichier
d’en-tête, header .h
Le mécanisme de template ressemble donc a une macro expansion ...
Frank Nielsen A1-40
fichier compare.h :
#i f n d e f COMPARE_H
#d e f i n e COMPARE_H
template <c l a s s T> i n t comp( const T& a , const T& b) {
i f ( a < b) r e t u r n −1;
i f (b < a ) r e t u r n 1;
r e t u r n 0;}
#e n d i f // COMPARE_H
fichier main.cpp :
#i n c l u d e <iostream >
#i n c l u d e "compare . h"
using namespace std ;
i n t main ( i n t argc , char ∗∗ argv )
{ cout << comp<int >(10 , 20) ; cout << endl ;
r e t u r n 0; }
Frank Nielsen A1-41
Lire un fichier dans un vector de la STL
Utiliser la classe vector de la STL pour les tableaux dynamiques !
i f s t r e a m f i n ;
f i n . open ( " f i c h i e r . t x t " ) ;
vector <s t r i n g > t e x t e ; s t r i n g mote ;
while ( f i n >> mot)
{ t e x t e . push_back (mot) ;}
f i n . c l o s e ( ) ;
◮ La boucle while lit jusqu’à temps de rencontrer EOF (End Of File)
◮ Les données sont des chaînes de caractères séparées par des délimiteurs
(espace, tab, retour à la ligne, point virgule pour les fichiers CSV,
Comma-Separated Values)
Frank Nielsen A1-42
STL : une collection de structures de données
Le concept fondamental est le containeur avec son iterator , le tout en
template !
Structure de données nom STL #include
tableau dynamique vector <vector>
liste chaînée list <list>
pile stack <stack>
file queue <queue>
arbre binaire set <set>
table de hachage unordered_map <set>
arbre binaire map <set>
tas ordonné file de priorité <queue>
Classes STL = structures de données abstraites (interfaces standardisées)
Les #include sont à faire sans le .h
Frank Nielsen A1-43
La STL : structures de données génériques
set <s t r i n g > mots ;
l i s t <Eleve> PromoX2014 ;
stack < vector <int > > nombres ;
À chaque container STL, on a un itérateur (iterator) associé de type
container<T>::iterator
set <s t r i n g >:: i t e r a t o r p=mots . f i n d ( " cours " ) ;
l i s t <Eleve >:: i t e r a t o r premier=PromoX2014 . begin () ;
stack < vector <int > >:: i t e r a t o r f i n=nombres . end () ;
On déreférence un itérateur comme pour un pointeur : *it
Frank Nielsen A1-44
Les containeurs stockent par valeur, pas par reférence
◮ quand on insére un objet, le containeur va en faire une copie
◮ quand le containeur doit réarranger les objets, il procéde en faisant des
copies de ceux-ci. Par exemple, si on tri, ou si on insére sur un containeur
map, etc.
◮ si on veut éviter cela, il faudra donc faire des containeurs de pointeurs !
C++11 a le mot clef auto pour inférer directemement les types et un
“foreach” (pour les curieux !) :
f o r ( vector <Printer >:: i t e r a t o r i t = vec . begin () ; i t < vec .
end () ; i t ++) { cout << ∗ i t << endl ; }
f o r ( auto i t = vec . begin () ; i t < vec . end () ; i t ++) { cout <<
∗ i t << endl ; }
Frank Nielsen A1-45
Fonctions membres communes à la STL
Toutes les classes containeurs ont les fonctions membres :
i n t s i z e ()
i t e r a t o r begin ()
i t e r a t o r end ()
bool empty ()
Pour lister tous les éléments d’un containeur, on fait :
l i s t <s t r i n g >:: i t e r a t o r i t=maListe . begin () ;
while ( i t != maListe . end () )
{ cout << ∗ i t <<endl ; i t e r ++;}
Notons que end() est un élément sentinel .
On ne peut pas déreférencer end().
Frank Nielsen A1-46
Différents accès aux éléments d’un containeur
◮ pour vector, on peut accéder aux éléments en utilisant un index [i] :
vector <int > vec442 ;
vec442 [0]=280;
... mais les crochets ne peuvent pas être utilisés pour list<int> par
exemple
◮ on peut rajouter un élément à la fin d’une liste ou d’un vecteur avec
push_back :
monVecteur . push_back (2013) ;
maListe . push_back (2013) ;
... mais il n’ y a pas de push_back pour les ensembles (codés par des
arbres binaires) :
set <int > monEnsemble ;
monEnsemble . push_back (2013) ; // Erreur ! ! !
Frank Nielsen A1-47
La liste (doublement chaînée)
On peut ajouter à la tête ou à la queue d’une liste en temps constant :
maListe . push_back (2013) ;
maListe . push_front (2015) ;
On peut insérer ou supprimer un élément avec un itérateur :
l i s t <s t r i n g >:: i t e r a t o r p=maListe . begin () ;
p=maListe . e r a s e (p) ;
p=maListe . i n s e r t (p , "HPC" ) ;
On peut avancer ou reculer dans une liste avec les opérateurs unaires ++ et -- :
p++; p−−; // faire attention aux débordements possibles
Seul bémol : on ne peut pas directement accéder i-ième élément (cela
demande de parcourir la liste, pas de crochets).
Frank Nielsen A1-48
La liste doublement chaînée en STL : itérateurs
Voir INF311/INF411
NULL
NULL
C++ HPC MPI
list<string>::iterator it=liste.find("HPC")
q=it-- q=it++
Frank Nielsen A1-49
Les piles et les files
◮ Piles ( stacks ) et files ( queues ) sont des sous-classes de la classe deque
◮ Une pile est une liste chaînée avec la propriété Dernier Arrivé Premier
Sorti, DAPS (LIFO : Last In First Out).
◮ Une file est une liste chaînée avec la propriété Premier Arrivé Premier
Sorti, PAPS (FIFO : First In First Out).
◮ On accéde au dernier élèement au sommet de la pile ou au premier
élément d’une file avec les primitives push et pop
◮ Pour les piles, on a aussi top, et pour les files front et back
Frank Nielsen A1-50
Les files de priorité
On doit définir un operator < .
La plus grande valeur est sur le haut (max-heap, top).
priority_queue <int > Q;
Q. push (23) ; Q. push (12) ; Q. push (71) ; Q. push (2) ;
cout << Q. top () ;
Q. pop () ;
cout << Q. top () ;
pour la plus petite valeur (min-heap), il faut donc changer le sens sémantique
de l’opérateur < ...
http://en.cppreference.com/w/cpp/language/operator_comparison
Frank Nielsen A1-51
On peut trier facilement avec une file de priorité...
#i n c l u d e <queue>
#i n c l u d e <iostream >
using namespace std ;
s t r u c t comparator {
bool operator () ( i n t i , i n t j ) { r e t u r n i < j ;}
};
i n t main ( i n t argc , char const ∗ argv [ ] )
{
priority_queue <int , std : : vector <int >, comparator>
minHeap ;
minHeap . push (10) ; minHeap . push (5) ;
minHeap . push (12) ; minHeap . push (3) ;
minHeap . push (3) ; minHeap . push (4) ;
while ( ! minHeap . empty () ) {
cout << minHeap . top () << " " ;
minHeap . pop () ;
}
r e t u r n 0;} // 12 10 5 4 3 3Frank Nielsen A1-52
Les ensembles : set (arbres binaires équilibrés)
On doit définir operator <. Toutes les valeurs sont uniques (sinon, utiliser
un multiset).
insert(value), erase(value), erase(iterator), iterator find(value)
set <s t r i n g > s ;
s . i n s e r t ( " Ecole " ) ;
s . i n s e r t ( " Polytechnique " ) ;
s . e r a s e ( " Ecole " ) ;
cout << ∗( s . f i n d ( " Polytechnique " ) ) ;
Frank Nielsen A1-53
Le hachage (map)
◮ Différence entre hachage fermé (tableau) et
hachage ouvert (tableau de pointeurs sur des listes).
◮ Templates pour la clef et le type de données map<K,T>.
◮ On doit définir operator < de comparaison pour le type K.
map<int , s t r i n g > monHachage ;
monHachage [23121981] = " A n n i v e r s a i r e Toto" ;
monHachage [05031953] = " A n n i v e r s a i r e T i t i " ;
. . .
map<s t r i n g , int > monHachageRev ;
monHachageRev [ "Toto" ] = 23121981;
monHachageRev [ " T i t i " ] = 05031953;
Frank Nielsen A1-54
Le hachage (map)
Les fonctions membres pour la classe STL map : erase(iterator),
erase(K clef), map_name(K key)
map<s t r i n g , int > M;
M[ "A" ] = 23;
M[ "B" ] = 12;
M[ "C" ] = 71;
M[ "D" ] = 5;
M. e r a s e ( "D" ) ;
cout << M[ "B" ] ;
Frank Nielsen A1-55
La classe STL paire à la rescousse
map<s t r i n g , int > maMap;
pair <s t r i n g , int > p a i r e ( "Tutu" , 606) ;
maMap. i n s e r t ( p a i r e ) ;
. . .
// on créé un nouvel enregistrement en faisant aussi :
maMap[ "Tata" ] = 707;
⇒ opérateur crochet [K]
Frank Nielsen A1-56
Les temps d’accés aux structures de données
Pour un containeur à n éléments :
vecteur list set map∗
Insérer/supprimer O(n) O(1) O(log n) ˜O(log n)
Rechercher O(n) O(n) O(log n) ˜O(log n)
map : implémentées historiquement avec des arbres binaires équilibrés
(red-black trees). Minimise le pire des temps !
unordered_map : implémentées avec des fonctions de hachage (temps amorti
en O(1))
Voir INF311/INF411.
Frank Nielsen A1-57
Les itérateurs
Chaque containeur est equipé d’un itérateur :
container <T>:: i t e r a t o r i t ;
i t=C. begin () ;
◮ ++ et – pour avancer ou reculer
◮ * pour déreférencer
◮ == et =! pour les tests de comparaisons
Seulement dans la classe vector, on peut bouger de p éléments (arithmétique)
en faisant
vector <T>:: i t e r a t o r i t ;
i t=i t+p ;
i t=i t −p ;
Frank Nielsen A1-58
Les itérateurs : premier et dernier éléments
Le dernier élément est une sentinelle :
cout << ∗(L . begin () ) ; // oui, si pas vide !
cout << ∗(L . end () ) ; // toujours non !
l i s t <s t r i n g >:: i t e r a t o r p = L . end () ;
p−−;
cout << ∗p ; // ok, si pas vide !
Frank Nielsen A1-59
Compiler des programmes
avec un
Makefile
Frank Nielsen A1-60
Compiler un programme
Exemple avec la fonction main dans le fichier main.cpp :
g++ -Wall -o monProg442.exe fonctions.cpp main.cpp
Les fichiers d’en-têtes (headers) en .h (templates) sont inclus dans les .cpp et
lus lors de la compilation de fichiers .cpp
Plus le programme (= ensemble de fichiers) devient gros, plus la ligne de
compilation devient grande à taper :
g++ -Wall -o monProg442.exe main.cpp fichier1.
cpp fichier2.cpp fichier3.cpp
Compilation avec l’option de débogage (option/ flag ’-g’) puis exécution dans
un déboggeur. Quand le programme crashe, il écrit un fichier core puis
débogage avec gdb, ou dans un IDE (Eclipse)
Que faire lorsqu’on a de nombreux fichiers à gèrer dans un projet ?
Frank Nielsen A1-61
Compilation dans un fichier compilé objet : les .o
Attention : ici objet n’a pas le sens de OO (orienté objet) !
g++ -c fichier.cpp
produit un fichier fichier.o
Dépend de l’architecture où a lieu la compilation : x86 32-bits ou 64-bits,
Oracle Sparc, MacOS, etc.
Par exemple, si vous compilez sous Windows, votre .o ne sera pas utilisable en
salles machines (UNIX).
C’est une grande différence avec Java qui compile en .class qui marche pour
la JVM (Java Virtual Machine), donc partout où on a une JVM !
Frank Nielsen A1-62
Graphe de dépendances d’un programme
Projet Programme
donnee.o main.o lecture.o
donnee.cpp donnee.h main.cpp lecture.h lecture.cpp
Comment faire pour recompiler si on a touché seulement au fichier
donnee.cpp ? Doit-on recompiler lecture.cpp en lecture.o ?
Frank Nielsen A1-63
L’utilitaire UNIX make
◮ utilitaire pour compiler ( building ) des programmes exécutables, des
bibliothèques, etc.
◮ organise les compilations, n’est pas spécifique à un langage donné
◮ utilise un script en entrée : Makefile
◮ on veut compiler un ensemble de cibles à partir de fichiers sources
correspondants
La commande touch permet de modifier les dates de dernière modification des
fichiers. Pour forcer la recompilation :
touch * ; make
Frank Nielsen A1-64
Les règles dans un Makefile
Les commandes doivent suivre une tabulation (pas des espaces !) :
target : source1 source2 ... sourceN
commande1
commande2
...
Exemple :
monProg : fichier1.cpp fichier2.cpp main.cpp
g++ -o monProg fichier1.cpp fichier2.cpp
main.cpp
Puis make target, par exemple :
make monProg
Frank Nielsen A1-65
Règle sans sources
On nettoie tous les fichiers :
clean :
rm fichier1.o fichier2.o fichier3.o monProg
puis par exemple ...
make clean
Frank Nielsen A1-66
Règle sans commandes
all: monProg monProg2
monProg: file1.o file2.o file3.o
gcc -g -Wall -o myprog file1.o file2.o file3
.o
monProg2: file4.c
gcc -g -Wall -o myprog2 file4.c
Il suffit alors de faire
make all
Frank Nielsen A1-67
Un aperçu du TD2
Frank Nielsen A1-68
Le TD2 : objets en C++ et récursivité
◮ nombres complexes C : constructeur, affichage, calcul du module
◮ quad-trees et requêtes géométriques
Frank Nielsen A1-69
Accès aux membres : o.v et ptro->v
#i n c l u d e <iostream >
#i n c l u d e <math . h>
using namespace std ;
c l a s s monome
{ p u b l i c : i n t d ;
monome( i n t dd ) : d( dd ) {}
double e v a l ( double x ) { r e t u r n pow( x , d) ;}
};
i n t main ()
{monome m(3) ; monome ∗ ptrm=&m;
cout<<m. e v a l (2)<<" "<<ptrm−>e v a l (3)<< endl ;
cout<<m. d<<" " <<ptrm−>d<<endl ;
r e t u r n 1;
}
Frank Nielsen A1-70
Le TD2 : quad-trees en 2D
Representation compacte d’une image binaire
Frank Nielsen A1-71
Octrees en 3D
Frank Nielsen A1-72
Octrees en infographie (proxy géométrique)
Frank Nielsen A1-73
Les trois concepts
fondamentaux d’Unix
Frank Nielsen A1-74
Trois concepts Unix
◮ Les tâches et signaux : ps, kill, sleep 500 &, Control-Z : interruption
, bg, fg
◮ Les entrées et sorties et opérateurs de redirection : monprog
<input.txt >output.txt
» pour rajouter (append)
command > /dev/null 2>&1
◮ Les commandes pipelinées : Compte le nombre de lignes des fichiers
concaténés
cat fichier1 fichier2 fichier3 | wc -l
Frank Nielsen A1-75
Les redirections
0 = STDIN, 1 = STDOUT, 2 = STDERR
pgm > file Output of pgm is redirected to file
pgm < file Program pgm reads its input from file
pgm » file Output of pgm is appended to file
n > file Output from stream with descriptor n redirected to file
n » file Output from stream with descriptor n appended to file
n >& m Merge output from stream n with stream m
n <& m Merge input from stream n with stream m
« tag Standard input comes from here through
next tag at start of line
Frank Nielsen A1-76
Résumé
la clustering hiérarchique (distance de base, distance d’ensembles)
structures récursives en C++
la généricité avec la bibliothèque C++ STL : la classe vector
// containeur
list<Eleve> PromoX2014;
// iterateur pour le containeur
list<Eleve>::iterator el=PromoX2014.begin();
// on dereference pour obtenir l’element
cout << (*el) <<endl;
// on incremente pour aller a l’element suivant
el++;
écrire un Makefile
trois concepts fondamentaux d’Unix
Frank Nielsen A1-77
Dendrogramme et partitionnement
Partition en 4 clusters à partir du dendrogramme.
Choisir une coupe (par forcément de hauteur constante).
Frank Nielsen A1-78
Dendrogramme : iris (4D)
Graphique d’un arbre binaire où la hauteur d’une branche est proportionnelle
à la distance entre les deux objets regroupés.
Frank Nielsen A1-79
Le clustering hiérarchique : single linkage (SL)
Saut minimum
D(Gi , Gj ) = min
xi ∈Gi ,xj ∈Gj
d(xi , xj )
Répeter tant que toutes les données xi ne soient pas contenues dans un seul
cluster.
À chaque instant tous les sous-arbres forment une forêt (partitition de X).
n − 1 étapes de fusion :
◮ Problème (artefact) de chainage dans le clustering final.
◮ Complexité : naïf O(n3), algorithme SLINK en O(n2).
Frank Nielsen A1-80
Le clustering hiérarchique : saut maximum/saut moyen
:
◮ Complete linkage (CL) : CLINK in O(n2) (1977)
D(Gi , Gj ) = max
xi ∈Gi ,xj ∈Gj
d(xi , xj )
→ très sensibles aux outliers, les artefacts de données
◮ Average linkage (AL) : O(n2) (1984)
D(Gi , Gj ) =
1
ni nj
xi ∈Gi xj ∈Gj
d(xi , xj )
Même complexité en temps quadratique pour les sauts
minimum/moyen/maximum
Frank Nielsen A1-81
Les piles : illustration
stack <s t r i n g > S ;
S . push ( "A" ) ;
S . push ( "B" ) ;
S . push ( "C" ) ;
S . pop () ;
Q. pop () ;
S . push ( "D" ) ;
Q. push ( "D" ) ;
cout << S . top () ;
Frank Nielsen A1-82
Les files : illustration
queue<s t r i n g > Q;
Q. push ( "A" ) ;
Q. push ( "B" ) ;
Q. push ( "C" ) ;
Q. pop () ;
Q. push ( "D" ) ;
cout << Q. f r o n t () << Q. back () ;
Frank Nielsen A1-83
La classe STL algorithm
Procédures (pas des méthodes de classe) : find, remove, count, shuffle,
replace, sort, for_each, min_element, binary_search, transform, copy,
swap :
i t e r = f i n d (L . begin () , L . end () , " Cours INF442" ) ;
i n t x = count (L . begin () , L . end () , " i n s c r i t en INF442" ) ;
r e p l a c e (L . begin () , L . end () , "DEP442" , "INF442" ) ;
_if : prend une fonction booléene utilisateur :
r e p l a c e _ i f (L . begin , L . end () , appartient442S , " Tutorat ")
;
Frank Nielsen A1-84
Édition de liens : linking
Édition de liens = phase finale de la compilation.
Rassemble tous les fichiers objets .o et produit un fichier exécutable.
Les fichiers objets utilisés proviennent de :
◮ de la compilation de fichiers .cpp (.cpp
g++ -c
−−−−→ .o)
◮ de la bibliothèque standard (fonctions E/Ss, fonctions mathématiques log,
exp, etc.)
◮ de bibliothèques extérieures (comme CImg lors du TD5)
g++ fichier1.o fichier2.o main.o -o monProg442.exe -
lpthread -lX11
Différence entre une bibliothèque statique .a (Unix, archive) .lib (Windows)
et une bibliothèque dynamique .so (Unix, shared objects) .dll (Windows,
dynamic linked library)
Frank Nielsen A1-85
Édition de liens : la commande ldd
ldd : print shared library dependencies (Linux)
#include <iostream >
using namespace std ;
i n t main ()
{ cout << "J ’ u t i l i s e un cout ! " ;
r e t u r n 0;}
ldd programme.exe
linux -gate.so.1 => (0 x00142000)
libstdc ++.so.6 => /usr/lib/libstdc ++.so.6 (0
x008f8000)
libm.so.6 => /lib/libm.so.6 (0 x0063c000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0
x008cc000)
libc.so.6 => /lib/libc.so.6 (0 x004de000)
/lib/ld -linux.so.2 (0 x004bf000)
Frank Nielsen A1-86
Les variables dans un Makefile
◮ déclaration d’une variable : NOM = valeur
◮ utilisation d’une variable : $(NOM)
Par exemple,
OBJFILES = file1.o file2.o file3.o
PROGRAM = myprog
$(PROGRAM): $(OBJFILES)
gcc -g -Wall -o $(PROGRAM) $(OBJFILES)
clean:
rm $(OBJFILES) $(PROGRAM)
Frank Nielsen A1-87
Makefile : partie générique
Idéalement, on aimerait paramétrer pour un ensemble d’architectures
(UNIX/Windows/MacOS/Sparc, etc.). Pour chaque architecture, le nom du
compilateur et ses options peuvent changer ...
CC = g++
CCFLAGS = -g -Wall
OBJFILES = file1.o file2.o file3.o
PROGRAM = myprog
$(PROGRAM): $(OBJFILES)
$(CC) $(CCFLAGS) -o $(PROGRAM) $(OBJFILES)
Bien d’autres possibilités plus étendues avec le Makefile
Frank Nielsen A1-88
Makefile : partie générique
◮ $@ : le fichier target courant
◮ $^ : la liste de tous les fichiers sources
◮ $< : la source la plus à gauche pour la cible courante
myprog: file1.o file2.o file3.o
gcc $(CCFLAGS) -o $@ $^
file1.o: file1.c file1.h file2.h
gcc $(CCFLAGS) -c $<
Frank Nielsen A1-89
Makefile : partie générique
BIN = JL_kmeans
OBJS = randomsample.o mathtools.o partition.o
FLAGS = -O3
INCLUDE = -I/usr/local/CImg -1.6.2/
LIBS = -L/usr/local/boost -1.58.0/ lib/
LDPATH = LD_LIBRARY_PATH =/usr/local/boost -1.58.0/ lib
:/usr/lib/alliance/lib
# exercice 0
cimgvec: cimgvec.cxx Makefile
$(CXX) $(FLAGS) $(INCLUDE) -o $@ $@.cxx $(
LIBS)
# exercice 1
imageresize: imageresize.cxx Makefile
$(CXX) $(FLAGS) $(INCLUDE) -o $@ $@.cxx $(
LIBS)
...Frank Nielsen A1-90
INF442 : Traitement des Données Massives
A3 : Le clustering avec les k-moyennes
et son extension en grandes dimensions avec Johnson-Lindenstrauss
Frank Nielsen
nielsen@lix.polytechnique.fr
X2014
20 avril 2016
Frank Nielsen A1-1
Règles pour le PA d’informatique
Programme d’Approfondissement Informatique :
https://programmes.polytechnique.fr/programme.php?id=999
◮ avoir validé un projet en cours d’Info de 2A (modal compris) : indiquez
cours et note a l’inscription
◮ au moins 2 cours d’info en 2A (hors modal)
Responsable 3A : Sylvie Putot putot@lix.polytechnique.fr
Frank Nielsen A1-2
Le regroupement (clustering)
= partitionner les données
en groupes homogènes
Frank Nielsen A1-3
Le clustering plat = partitionner les données
k = 3 clusters :
Partition
Chaque cluster a un représentant ⊗= prototype du cluster
Frank Nielsen A1-4
Exemple de clustering : observations du ciel
Trouver les galaxies = amas d’objets célestes (=groupe, =cluster)
Sloan Digital Sky Survey http://www.sdss.org/
plus de 3 millions d’objets célestes
Frank Nielsen A1-5
Dans les faits, on a une soupe d’attributs par donnée ...
Jeu de n = 4898 données sur les vins, d = 11 attributs
https://archive.ics.uci.edu/ml/datasets/Wine+Quality
fixed acidity ;" volatile acidity ";" citric acid ";" residual sugar ";" chlorides ";" free sulfur
dioxide ";" total sulfur dioxide ";" density ";" pH ";" sulphates ";" alcohol ";" quality"
7;0.27;0.36;20.7;0.045;45;170;1.001;3;0.45;8.8;6
6.3;0.3;0.34;1.6;0.049;14;132;0.994;3.3;0.49;9.5;6
...
1 - fixed acidity
2 - volatile acidity
3 - citric acid
4 - residual sugar
5 - chlorides
6 - free sulfur dioxide
7 - total sulfur dioxide
8 - density
9 - pH
10 - sulphates
11 - alcohol
On veut grouper les vins par “ressemblances” (par qualité, même qualité =
même groupe).
Attributs numériques ou catégoriques
⇒ définir la bonne notion de similarité/distance
Frank Nielsen A1-6
Recherche exploratoire : Le regroupement (clustering)
Partitionner les données :
◮ X = {x1, ..., xn}, n données , chacune comportant d attributs :
xi = (x
(1)
i , ..., x
(j)
i , ..., x
(d)
i ).
Partitionne X en k ∈ N groupes disjoints = clusters :
X = G1 ∪ G2 ∪ ... ∪ Gk, Gi ∩ Gj = ∅, ∀i = j
◮ permet de catégoriser les données en donnant un sens sémantique aux
groupes homogènes → c’est l’apprentissage non-supervisé.
◮ Pour chaque groupe Gi , on peut définir un centre ci , appelé prototype
ou représentant du cluster (sous-classe d’algorithmes appelé center-based
clustering)
◮ ... mais le clustering/regroupement sert aussi à une quantité d’autres
algorithmes ...
Frank Nielsen A1-7
Partitionner les données : le clustering
Problème avec 3 types de grandeurs :
◮ n : le nombre de données
◮ d : la dimension des données
X est visualisé comme un nuage de points dans Rd
Attributs numériques, catégorielles ou semi-catégorielles
◮ k : le nombre de clusters (k ≤ n avec souvent k ≪ n)
souvent inconnu a priori
Généralement, on a n ≫ d (n très grand devant d)
et k ≪ n (k très petit devant n, négligeable) inconnu,
mais on peut aussi avoir d ≫ n et k = Θ(n)
Notation : a ≫ b si a > b et a
b = constante
exp n ≫ n2 ≫ n ≫ log n
n1+ǫ ≫ n loga
n ∀ǫ > 0, a ∈ N
Frank Nielsen A1-8
Commençons avec le cas simple : k = 1 cluster
Question = Comment trouver le centre ( = prototype) du cluster ?
Un critère est de minimiser la variance du cluster = sa dispersion :
v(X, c1) =
n
i=1
xi − c1
2
avec p − q 2 = d
j=1(p(j) − q(j))2, la distance Euclidienne au carré
p − q 2 = p − q, p − q où x, y = d
j=1 x(j)y(j) = produit scalaire
On veut minimiser :
min
c1
v(X, c1) = min
c1
n
i=1
xi − c1
2
Minimiser v(X, c1) ≡ minimiser 1
n v(G1, c1) (sa normalisation).
Frank Nielsen A1-9
Centre et variance d’un cluster
◮ Variance du cluster : minimise v1(X, c)
min
c
v1(X, c) =
n
i=1
xi − c 2
◮ Centre du cluster :
c1 = arg min
c
v(X, c) = arg min
c
n
i=1
xi − c 2
, v1(X) = v1(X, c1)
arg min renvoie l’argument qui a donné lieu au minimum.
En cas d’égalité, on renvoie le plus petit suivant un ordre donné.
Par exemple, pour un tableau
t[0] = −3, t[1] = 5, t[2] = −7, t[3] = 10, t[4] = −7, t[5] = 12. ordre ≤ sur les
indexes entiers (ordre lexicographique)
min
i
t[i] = −7, arg min
i
t[i] = 2
Frank Nielsen A1-10
Rappel sur l’optimisation convexe
◮ Une fonction f ∈ C2 est
strictement convexe ssi. pour
x = y, ∀α ∈ (0, 1)
f (αx+(1−α)y) < αf (x)+(1−α)f (y)
◮ équivalent à f ′′(x) > 0 (x ∈ R)
◮ minimum unique x∗ ssi
∃!x∗, f ′(x∗) = 0 (peut ne pas
exister comme pour ex )
◮ Analyse multivariée : vecteur
Jacobien ∇x f (x) = (∂f (x)
∂xi
)i et
matrice Hessienne
∇2
x f (x) = (∂2f (x)
∂xi ∂xj
)i,j ≻ 0
matrice positive définie
x y
(x, f(x))
(y, f(y))
αx + (1 − α)y
f(αx + (1 − α)y)
αf(x) + (1 − α)f(y)
z = f(x)
f(x)
f(y)
x∗
f(x∗
)
Frank Nielsen A1-11
Centre de masse, centre de gravité ou centroïde
Montrons que c1 = 1
n
n
i=1 xi = ¯x, est le centre de masse appelé aussi
centroïde .
min
c1
n
i=1
xi − c1, xi − c1 =
n
i=1
( xi , xi − 2 xi , c1 + c1, c1 )
n
i=1 xi , xi est une constante, et mettons donc à zéro les dérivées partielles
de e(c1) = n
i=1(−2 xi , c1 + c1, c1 ).
∇c1 e1(c1) =
n
i=1
(−2xi + 2c1) = 0 ⇒ c1 =
1
n
n
i=1
xi
c1 est unique car les dérivées partielles secondes ∇2
c1
e1(c1) = diag(2, 2, ..., 2)
sont strictement positives : e(c1) est donc strictement convexe.
Frank Nielsen A1-12
Illustration : petite et grande variances (dispersions)
Petite
et grande variance (dispersion) d’un cluster autour de son centre :
v1(G1) =
1
n
n
i=1
xi −
1
n
n
l=1
xl
2
v1(G1) =
1
n
n
i=1
xi
2
− ¯x 2
, ¯x =
1
n
n
i=1
xi
Frank Nielsen A1-13
Le clustering par la fonction objective des k-moyennes
On cherche à trouver les groupes avec les k centres c1, ..., ck (prototypes) qui
minimise la fonction de coût ou fonction objective des k-moyennes :
ek(X; c1, ..., ck) = ek(X; C) =
n
i=1
min
j∈{1,...,k}
xi − cj
2
C’est équivalent à
ek(X; C) =
k
j=1 x∈Gj
x − cj
2
avec
Gj = {xi ∈ X : xi − cj ≤ xi − cl , ∀l ∈ {1, ..., k}}
NB : En cas d’égalité des distances, on affecte suivant l’ordre lexicographique
des clusters afin de respecter la propriété de partition .
→ On veut minimiser la somme pondérée des variances des clusters
= somme des dispersions des clusters
Frank Nielsen A1-14
Tractabilité du clustering par les k-moyennes
◮ Calculer un clustering 1-moyenne coûte O(dn) (temps linéaire)
◮ Minimiser la fonction de coût des k-moyennes est NP-dur quand d > 1
et k > 1
◮ Polynomial en temps O(n2k) quand d = 1 (1 attribut/donnée) par
programmation dynamique
→ On va donc chercher des heuristiques pour résoudre les k-moyennes quand
k > 1 et d > 1.
Frank Nielsen A1-15
Heuristiques pour les k-moyennes
◮ Heuristiques globales : on cherche les k centres des groupes sans
configuration initiale des centres
◮ Heuristiques locales : on part d’une configuration des k centres, et on
améliore localement avec des itérations la solution jusqu’à temps de
converger vers un minimum local.
Frank Nielsen A1-16
Heuristique : initialisation aléatoire
◮ choisir les k graines distinctes (seeds) aléatoirement dans X.
Méthode dite de Forgy
centres initiaux = éléments de X
◮ choisir aléatoirement dans une boîte englobante qui contient les données
◮ Initialisation probabilies avec les k-moyennes++
◮ etc.
Frank Nielsen A1-17
Heuristique de Lloyd : algorithme itératif “batch”
À partir d’une configuration G1, ..., Gk (avec les centres c1, ..., ck), on améliore
itérativement la solution avec ces deux étapes :
Allocation des données aux groupes.
Pour tout xi ∈ X, soit li = arg minl xi − cl
2, et formons les
groupes Gj = {xi : li = j} de cardinalité nj = |Gj |.
(ici, distance ou distance au carré donne la même allocation)
Mise à jour des centres des groupes.
Pour tout j ∈ [k] = {1, ..., k}, calculer le centre de masse :
cj = 1
nj x∈Gj
x. On a donc minimisé pour chaque cluster
1
nj x∈Gj
x − cj
2.
Si on remplace distance au carré par distance, on obtient le point
de Fermat-Weber qui n’admet pas de formule close.
Répeter ces deux étapes jusqu’à convergence ou amélioration de la fonction
objective qui passe sous un seuil.
Frank Nielsen A1-18
Allocation des données aux groupes : partition de Voronoï
c1
c2
c3c4
c5
c6
p|lC(p) = 1
q|lC(q) = 3
Vj = {x ∈ Rd
: x − cj ≤ x − cl , ∀l ∈ {1, ..., n}}.
lC (x) = arg
k
min
j=1
x − cj
2
Frank Nielsen A1-19
Convergence de l’algorithme itératif de Lloyd
Théorème
Les k-moyennes de Lloyd converge de façon monotone en un nombre fini
d’étapes.
Soit G(Ct) = {G
(t)
1 , ..., G
(t)
k } la partition de X à l’étape t de coût ck(X, Ct).
A l’étape t + 1, puisqu’on alloue les points aux clusters dont les centres sont
les plus proches, on minimise donc :
ck(G(C(t+1)
), Ct) ≤ ck(X, Ct)
Rappelons que l’on a ck(G(C(l)), Cl ) = k
j=1 v(G
(l)
j , cj ) (somme des variances
des clusters).
Lors de la remise à jour des centres par les centroïdes des groupes, pour
chaque groupe on a v(G
(t+1)
j , c(t+1) = c(G
(t+1)
j )) ≤ v(G
(t+1)
j , c
(t)
j ), et donc :
ck(X, Ct+1) ≤ ck(G(C(t+1)
), Ct) ≤ ck(X, Ct)
Frank Nielsen A1-20
L’heuristique de Lloyd en action : les points initiaux
n = 16 points (•) et k = 2 graines (×)
Frank Nielsen A1-21
L’heuristique de Lloyd en action
affectation
des points aux centres (étape 1)
Frank Nielsen A1-22
L’heuristique de Lloyd en action
nouveaux centres
= centroïdes des groupes (étape 1)
Frank Nielsen A1-23
L’heuristique de Lloyd en action
affectation
des points aux centres (étape 2)
Frank Nielsen A1-24
L’heuristique de Lloyd en action
nouveaux centres
= centroïdes des groupes (étape 2)
Frank Nielsen A1-25
L’heuristique de Lloyd en action
convergence : lorsque les points sont alloués aux mêmes groupes (étape 3) que
lors de la précédente itération
étape 2 étape 3
Frank Nielsen A1-26
Démo
Les k-moyennes de Lloyd
Frank Nielsen A1-27
Algorithme de Lloyd : le cas des clusters vides
On peut avoir des clusters qui deviennent vides (cas “rares” en pratique mais
qui augmente avec la dimension !).
Dans ce cas, on peut partiellement rechoisir une ou des nouvelles graines, et la
somme des variances des clusters continue à diminuer (partial reseeding)
Frank Nielsen A1-28
Un nombre potentiel exponentiel de minima locaux !
La fonction de coût des k-moyennes peut avoir un nombre exponentiel de
minima locaux.
◮ minimum global 0.375 : (a) et (b)
◮ minima locaux ∼ 0.5417 : (c) et (d)
On réplique ce sous-ensemble en paquets en les éloignant très loins les uns des
autres
Frank Nielsen A1-29
Algorithme de Lloyd (1957)
◮ En théorie, l’heuristique de Lloyd peut boucler un nombre
exponentiellement de fois (linéaire en 1D). ... et souvenons nous que
minimiser les k-moyennes sont NP-durs
◮ Marche expérimentalement très bien : implémenter un critère pour
stopper les itérations lorsque la décroissance de la fonction de coût passe
sous un seuil donné : Par exemple, ek(X, Ct) − ek(X, Ct+1) ≤ ǫ (ou seuil
relatif en pourcentage).
◮ Complexité de Lloyd : O(dn) en mémoire et O(dns) où s = nombre
d’itérations.
◮ ⇒ de nombreuses variantes et analyses de complexité !
Frank Nielsen A1-30
k-moyennes : le choix du nombre de clusters k
◮ Un problème important : déterminer le nombre de clusters k
◮ Pour n’importe quel k, on a la fonction k-moyenne optimale ek(X)
(évaluer empiriquement avec l’heuristique de Lloyd sur plusieurs
initialisations)
◮ ek(X) décroit de façon monotone jusqu’à en(X) = 0
Cas limite : un point par cluster ⇒ variance nulle
Méthode du coude : on dessine la fonction (k, ek(X)) et on choisit k au
niveau du coude (elbow).
k
2 3 4 5 6 7 8 9 10
fonctiondecoˆutdesk-moyennesek(X)
avant-brasbras
coude
Frank Nielsen A1-31
Les limitations de la technique des k-moyennes
Permet de trouver des clusters dont les enveloppes convexes des groupes sont
deux à deux séparables (propriété des diagrammes de Voronoï).
Par exemple, ne permet pas de partitionner correctement ce jeu de données :
Pour information, ce problème est résolu par les k-moyennes à noyau
Frank Nielsen A1-32
Vérité terrain (groundtruth)
◮ Sans vérité terrain, une analyse subjective des clusters permet de mettre
en valeur telle ou telle technique de clustering.
Mais quand d > 3 comment visualiser ?
→ Réduction de dimension linéaire (ACP) ou apprentissage de variétés
(manifold learning)
◮ Lorsque l’on dispose de vérités terrains par des jeux de données dont on
connaît déjà l’appartenance aux clusters (c’est-à-dire la classe pour
chaque donnée), on peut calculer divers indexes qui montrent la
concordance du résultat avec celui étiqueté (supposé optimal).
◮ Notez le problème ambigü de l’étiquettage puisque les clusters ne sont pas
forcément numérotés avec les mêmes numéros : on doit faire face
potentiellement à k! permutations.
Frank Nielsen A1-33
L’indexe de Rand : similarité entre deux clusterings
indexe de Rand
= Mesure de similarité entre deux clusterings G = ⊎Gi et G′ = ⊎G′
i (disons,
celui obtenu par les k-moyennes et un jeu de données correctement étiqueté).
Compare toutes les n
2 paires (xi , xj ) de points et compte ceux qui se trouvent
dans les mêmes clusters (a) et ceux qui se trouvent dans des clusters différents
(b).
R(G, G′
) =
a + b
n
2
, 0 ≤ R ≤ 1
◮ a : #{(i, j) : l(xi ) = l(xj ) ∧ l′(xi ) = l′(xj )}
◮ b : #{(i, j) : l(xi ) = l(xj ) ∧ l′(xi ) = l′(xj )}
Condition1 ∧ Condition2 : vrai ssi. Condition 1 et 2 sont vraies
On a évité ainsi de renuméroter les k groupes (k! permutations).
Frank Nielsen A1-34
Parallélisation des
k-moyennes
Parallel k-means
Frank Nielsen A1-35
Parallélisation : propriété de (dé)composition du centroïde
X et X′ : deux jeux de données pondérées
¯x(X) : barycentre de X, ¯x(X) = 1
w(X) x∈X w(x)x
W = w(X) = x∈X w(x) et W ′ = w(X′).
Décomposabilité du barycentre :
¯x(X ∪ X′
) =
W
W + W ′
¯x(X) +
W ′
W + W ′
¯x(X′
)
◮ très utile pour partager le calcul des données sur plusieurs processeurs ...
◮ propriété de la géométrie Euclidienne
(par exemple, n’est pas vrai en géométrie hyperbolique)
Frank Nielsen A1-36
Parallélisation de l’heuristique de Lloyd
Soit p processus/processeurs P0, ..., Pp−1
Chaque machine/processus a sa propre mémoire vive
n données, d dimensions/donnée (= attributs)
◮ au départ, tous les processus lisent leurs données, ou alors le processus
racine partitionne et envoie les données à tous les autres processus =
diffusion, une opération de communication globale
◮ Le processus racine choisit les k graînes (= prototypes initiaux), et les
diffuse à tous les autres processus
◮ chaque processus Pr s’occupe d’ un paquet de n
p données
Xr = {xr n
p
...x(r+1) n
p
−1} en calculant la distance minimale de ses xi aux
centres. On met à jour la fonction de coût, et on calcule les centroïdes et
cardinalité indépendamment dans chaque paquet : G1(r), ..., Gk(r) avec
n1(r) = |G1(r)|, ..., nk(r) = |Gk(r)|.
Frank Nielsen A1-37
Parallélisation de l’heuristique de Lloyd
◮ puis on agrége tous les cj (r) et nj (r) (opération reduce) en faisant des
opérations de sommes cumulées (= calcul collaboratif)
◮ et on répète jusqu’à convergence, ou lorsque la décroissance de la fonction
de coût passe sous un seuil.
Frank Nielsen A1-38
Frank Nielsen A1-39
Les k-moyennes en parallèle : analyse de la complexité
◮ Les opérations élémentaires de communications globales comme la
diffusion (Bcast) et de calculs globaux comme l’agrégation (Reduce)
dépendent de comment les machines sont reliées entre elles =
topologie du réseau d’interconnexion du cluster de machines .
◮ Initialisation des centres initiaux par le processeur racine P0 en temps
O(dk)
◮ Coût total de la parallélisation :
O dk + Bcast(p, dk) + s
dn
p
+ Reduce(p, dk) ∼n≫k,d O
dkns
p
◮ → Facteur d’accélération (speed-up, rapport du temps séquentiel sur le
temps parallèle) α = O dkns
dkns
p
= O(p).
Frank Nielsen A1-40
Réduction de dimension
linéaire avec le théorème de
Johnson-Lindenstrauss
Frank Nielsen A1-41
Le fléau des grandes dimensions !
Curse of dimensionality
Bellman, inventeur de la programmation dynamique
◮ efficacité des algorithmes dépend de la dimension d des attributs :
◮ calcul de distances ou de similarités en Ω(d)
◮ algorithmes et structures de données souvent avec une constante
exponentielle en d cachée dans la notation O(·) : Od (1).
◮ difficile de visualiser les données en grandes dimensions
◮ dimension ambiante (= extrinséque) versus dimension intrinsèque
Aujourd’hui, dans le traitement des données :
◮ très courant de travailler en dimension 1000 et bien plus !
◮ cas aussi où d ≫ n (dimension extrinséque ≫ dimension intrinséque)
Frank Nielsen A1-42
Des phénoménes non-intuitifs en grandes dimensions !
◮ volume de la balle inscrite dans le cube unité tend vers zéro :
Bd =
π
d
2
Γ(d
2 + 1)
rd
, r =
1
2
, Γ(t) =
∞
0
xt−1
e−x
dx
◮ grille régulière de Rd en l sous-divisions par côté partitionne l’espace en ld
hypercubes : exponentiel en d (ld = ed log l ).
L’approche de la grille adaptative ne permet pas non plus de passer à
l’échelle ...
◮ intégration stochastique à la Monte-Carlo ( ≈ ) devient inutilisable ...
◮ on ne distingue plus le plus proche voisin du plus lointain voisin ...
“... the distance to the nearest data point approaches the distance to the
farthest data point ...” (Beyer, 1999)
Frank Nielsen A1-43
Exemple 1 : trouver les images dupliquées
Problème : near duplicate image detection
◮ une image I[y][x] en couleur RVB de taille w × h est convertie en un
vecteur v(I) de dimension R3wh (vectorization)
◮ la distance entre deux images I1 et I2 est la somme des différences au
carré ( sum of squared differences ) :
SSD(I1, I2) =
h
i=1
w
j=1
(I1[i][j] − I2[i][j])2
= v(I1) − v(I2) 2
◮ une image est en double dans une base d’images si son Plus Proche Voisin
(PPV) est quasiment identique : SSD(I, PPV(I)) ≤ ǫ
⇒ comment calculer les plus proches voisins en grandes dimensions en temps
sous-linéaire, o(d) ?
Frank Nielsen A1-44
Exemple 2 : regrouper une collection d’images
Exemple de la base MNIST des chiffres postaux (US) :
n = 60000, d = 282 = 784
Idéalement, trouver les dix clusters pour les chiffres de ’0’ à ’9’
◮ utiliser l’algorithme des k-moyennes de Lloyd en dimension 784 est trop
lent ...
◮ comment faire ?
→ réduire la dimension en conservant la notion de distance
http://yann.lecun.com/exdb/mnist/
Frank Nielsen A1-45
La réduction de dimension : formuler le problème
◮ données X : n points de Rd
◮ X interprété comme une matrice de taille n × d
une donnée par ligne, vecteur ligne = matrice fine (thin vs fat matrix)
◮ Deux techniques pour réduire la dimension :
◮ sélectionner les dimensions à conserver (feature selection)
◮ recomposer les dimensions existantes en de nouvelles dimensions tout en
gardant l’“information” (la notion de distance)
Frank Nielsen A1-46
La réduction de dimension linéaire
Associons un vecteur y = y(x) ∈ Rk à tout x ∈ Rd :
A : Rd
→ Rk
Lorsque y(x) est une fonction linéaire, écriture matricielle :
y
(1,k)
= x
(1,d)
× A
(d,k)
, Y = X × A
A matrice de taille d × k (x et y = vecteurs lignes)
⇒ Y doit être “fidèle” à X :
∀x, x′
∈ X, y − y′ 2
= xA − x′
A 2
≈ x − x 2
X × A : représentation compacte de X, taille kn au lieu de dn
Frank Nielsen A1-47
Le théorème de Johnson-Lindenstrauss (1984)
Soit X n points de Rd et ǫ ∈ (0, 1), alors il existe une transformation linéaire
A : Rd → Rk avec k = O( 1
ǫ2 log n) telle que :
∀x, x′
∈ X, (1 − ǫ) x − x′ 2
≤ xA − x′
A 2
≤ (1 + ǫ) x − x′ 2
→low distortion embedding
(différent du cas où c’est parfait = plongement iso-métrique)
On passe de la dimension d à la dimension k = O( 1
ǫ2 log n)
C’est indépendant de la dimension ambiante d ! ! !
Frank Nielsen A1-48
Matrices A pour les projection aléatoires
Projection aléatoire A :
◮ On tire les coefficients de la matrice A′ aléatoirement suivant une loi
normale/Gaussienne standard (iid) :
A′
= [ai,j ], ai,j ∼ N(0, 1)
◮ On obtient un échantillon aléatoire d’une loi normale standard N(0, 1) à
partir de lois uniformes U1 et U2 indépendantes par :
N = −2 log U1 cos(2πU2)
← transformation de Box-Müller
◮ on ajuste l’échelle :
A =
k
d
A′
Frank Nielsen A1-49
Pourquoi ça marche : les projections aléatoires
◮ soit un espace k-affine aléatoire A avec k ≥ 4 log n
ǫ2
2
− ǫ3
3
.
◮ notons ˜x = d
k projAx = projection orthogonale de x sur A.
Lemme :
∀p, q ∈ X, P
˜p − ˜q 2
p − q 2
∈ [1 − ǫ, 1 + ǫ] ≤
2
n2
◮ Preuve : Probabilité que ˜x satisfasse le théorème JL :
≥ 1 −
n
2
2
n2
=
1
n
◮ On peut choisir O(n) projections et garantir une probabilité de succès
constante
Frank Nielsen A1-50
Résultats récents sur les transformations de
Johnson-Lindenstrauss
◮ k = Ω(ǫ−2 log n), optimal pour les transformations linéaires
The Johnson-Lindenstrauss lemma is optimal for linear dimensionality
reduction, 2014
◮ matrice avec poids dans Z (Achlioptas, 2003) :
ai,j =



1 avec probabilité 1
6
0 avec probabilité 2
3
−1 avec probabilité 1
6
◮ matrices creuses : O(1
ǫ ) coefficients non-nuls/ligne
Sparser Johnson-Lindenstrauss transforms, J. ACM, 2014
Frank Nielsen A1-51
Le TD d’aujourd’hui ... Regrouper des images !
Implémenter les “Johnson-Lindenstrauss k-moyennes” pour une base d’images !
On va passer de R300×300×3 = R270000 à R532 tout en trouvant des partitions
semblables ...
Grand gain de rapidité !
Complexité passant de O(sdkn) à Oǫ(skn log n) où s est le nombre d’itérations
(avec Oǫ(nd log n) pour calculer les projections)
Utiliser une bibliothèque externe CImg, rentrer dans du code C++ STL
Frank Nielsen A1-52
Le TD d’aujourd’hui ... Regrouper des images !
Quelques images retournées par une requête ’spaghetti’ d’un moteur de
recherche :
Frank Nielsen A1-53
Le TD d’aujourd’hui ... Regrouper des images !
Ces images regroupées en thème ( = clusters) :
Frank Nielsen A1-54
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016
Traitement massif des données 2016

Contenu connexe

En vedette

Traitement des données massives (INF442, A3)
Traitement des données massives (INF442, A3)Traitement des données massives (INF442, A3)
Traitement des données massives (INF442, A3)Frank Nielsen
 
Patch Matching with Polynomial Exponential Families and Projective Divergences
Patch Matching with Polynomial Exponential Families and Projective DivergencesPatch Matching with Polynomial Exponential Families and Projective Divergences
Patch Matching with Polynomial Exponential Families and Projective DivergencesFrank Nielsen
 
Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Frank Nielsen
 
Traitement des données massives (INF442, A7)
Traitement des données massives (INF442, A7)Traitement des données massives (INF442, A7)
Traitement des données massives (INF442, A7)Frank Nielsen
 
On representing spherical videos (Frank Nielsen, CVPR 2001)
On representing spherical videos (Frank Nielsen, CVPR 2001)On representing spherical videos (Frank Nielsen, CVPR 2001)
On representing spherical videos (Frank Nielsen, CVPR 2001)Frank Nielsen
 
Computational Information Geometry for Machine Learning
Computational Information Geometry for Machine LearningComputational Information Geometry for Machine Learning
Computational Information Geometry for Machine LearningFrank Nielsen
 
A series of maximum entropy upper bounds of the differential entropy
A series of maximum entropy upper bounds of the differential entropyA series of maximum entropy upper bounds of the differential entropy
A series of maximum entropy upper bounds of the differential entropyFrank Nielsen
 
Divergence center-based clustering and their applications
Divergence center-based clustering and their applicationsDivergence center-based clustering and their applications
Divergence center-based clustering and their applicationsFrank Nielsen
 

En vedette (8)

Traitement des données massives (INF442, A3)
Traitement des données massives (INF442, A3)Traitement des données massives (INF442, A3)
Traitement des données massives (INF442, A3)
 
Patch Matching with Polynomial Exponential Families and Projective Divergences
Patch Matching with Polynomial Exponential Families and Projective DivergencesPatch Matching with Polynomial Exponential Families and Projective Divergences
Patch Matching with Polynomial Exponential Families and Projective Divergences
 
Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)
 
Traitement des données massives (INF442, A7)
Traitement des données massives (INF442, A7)Traitement des données massives (INF442, A7)
Traitement des données massives (INF442, A7)
 
On representing spherical videos (Frank Nielsen, CVPR 2001)
On representing spherical videos (Frank Nielsen, CVPR 2001)On representing spherical videos (Frank Nielsen, CVPR 2001)
On representing spherical videos (Frank Nielsen, CVPR 2001)
 
Computational Information Geometry for Machine Learning
Computational Information Geometry for Machine LearningComputational Information Geometry for Machine Learning
Computational Information Geometry for Machine Learning
 
A series of maximum entropy upper bounds of the differential entropy
A series of maximum entropy upper bounds of the differential entropyA series of maximum entropy upper bounds of the differential entropy
A series of maximum entropy upper bounds of the differential entropy
 
Divergence center-based clustering and their applications
Divergence center-based clustering and their applicationsDivergence center-based clustering and their applications
Divergence center-based clustering and their applications
 

Similaire à Traitement massif des données 2016

20160216 - From BigData to BigProcessing
20160216 - From BigData to BigProcessing20160216 - From BigData to BigProcessing
20160216 - From BigData to BigProcessingPierre-Marie Brunet
 
Chapitre 4: Architecture simplifiée d’un ordinateur
Chapitre 4: Architecture simplifiée d’un ordinateur Chapitre 4: Architecture simplifiée d’un ordinateur
Chapitre 4: Architecture simplifiée d’un ordinateur Mohamed Lahby
 
Architectures parallèles.pdf
Architectures parallèles.pdfArchitectures parallèles.pdf
Architectures parallèles.pdfYasmineChihab1
 
Theme1 (1)
Theme1 (1)Theme1 (1)
Theme1 (1)salmazen
 
Cours de microcontrôleurs
Cours de microcontrôleursCours de microcontrôleurs
Cours de microcontrôleurssarah Benmerzouk
 
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]Antoine Poliakov
 
Chapitre 3-architecture-des-dsp
Chapitre 3-architecture-des-dspChapitre 3-architecture-des-dsp
Chapitre 3-architecture-des-dspgharbisalah
 
large scale multiprocessors et leurs application scientifique
large scale multiprocessors et leurs application scientifique large scale multiprocessors et leurs application scientifique
large scale multiprocessors et leurs application scientifique Abdelkrim Bournane
 
Chap XIII : calcul scientifique avec python
Chap XIII : calcul scientifique avec pythonChap XIII : calcul scientifique avec python
Chap XIII : calcul scientifique avec pythonMohammed TAMALI
 
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]ANEO
 
Cours Benhabiles TMS320.pdf
Cours Benhabiles TMS320.pdfCours Benhabiles TMS320.pdf
Cours Benhabiles TMS320.pdfHouBou3
 
Lepton : Description succincte
Lepton : Description succincteLepton : Description succincte
Lepton : Description succincteO10ée
 
Offre d'emploi Ingénieur intégration système LINUX H/F
Offre d'emploi Ingénieur intégration système LINUX H/FOffre d'emploi Ingénieur intégration système LINUX H/F
Offre d'emploi Ingénieur intégration système LINUX H/FSimstream
 
La technologie des systemes distribués 2 ppt2222.pptx
La technologie des systemes distribués 2 ppt2222.pptxLa technologie des systemes distribués 2 ppt2222.pptx
La technologie des systemes distribués 2 ppt2222.pptxkaoutarghaffour
 
Cours de PIC Généralités.pdf
Cours de PIC Généralités.pdfCours de PIC Généralités.pdf
Cours de PIC Généralités.pdfAliRami3
 

Similaire à Traitement massif des données 2016 (20)

20160216 - From BigData to BigProcessing
20160216 - From BigData to BigProcessing20160216 - From BigData to BigProcessing
20160216 - From BigData to BigProcessing
 
Chapitre 4: Architecture simplifiée d’un ordinateur
Chapitre 4: Architecture simplifiée d’un ordinateur Chapitre 4: Architecture simplifiée d’un ordinateur
Chapitre 4: Architecture simplifiée d’un ordinateur
 
Architectures parallèles.pdf
Architectures parallèles.pdfArchitectures parallèles.pdf
Architectures parallèles.pdf
 
Theme1 (1)
Theme1 (1)Theme1 (1)
Theme1 (1)
 
Cours de microcontrôleurs
Cours de microcontrôleursCours de microcontrôleurs
Cours de microcontrôleurs
 
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Retour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
 
Wygday 2008
Wygday 2008Wygday 2008
Wygday 2008
 
Cour1
Cour1Cour1
Cour1
 
Chapitre 3-architecture-des-dsp
Chapitre 3-architecture-des-dspChapitre 3-architecture-des-dsp
Chapitre 3-architecture-des-dsp
 
large scale multiprocessors et leurs application scientifique
large scale multiprocessors et leurs application scientifique large scale multiprocessors et leurs application scientifique
large scale multiprocessors et leurs application scientifique
 
Chap XIII : calcul scientifique avec python
Chap XIII : calcul scientifique avec pythonChap XIII : calcul scientifique avec python
Chap XIII : calcul scientifique avec python
 
Tiny os_2
Tiny os_2Tiny os_2
Tiny os_2
 
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
Tech daysRetour d’expérience Big Compute & HPC sur Windows Azure [TechDays 2014]
 
HADOOP + R
HADOOP + RHADOOP + R
HADOOP + R
 
Cours Benhabiles TMS320.pdf
Cours Benhabiles TMS320.pdfCours Benhabiles TMS320.pdf
Cours Benhabiles TMS320.pdf
 
Lepton : Description succincte
Lepton : Description succincteLepton : Description succincte
Lepton : Description succincte
 
Offre d'emploi Ingénieur intégration système LINUX H/F
Offre d'emploi Ingénieur intégration système LINUX H/FOffre d'emploi Ingénieur intégration système LINUX H/F
Offre d'emploi Ingénieur intégration système LINUX H/F
 
La technologie des systemes distribués 2 ppt2222.pptx
La technologie des systemes distribués 2 ppt2222.pptxLa technologie des systemes distribués 2 ppt2222.pptx
La technologie des systemes distribués 2 ppt2222.pptx
 
DSP
DSPDSP
DSP
 
Cours de PIC Généralités.pdf
Cours de PIC Généralités.pdfCours de PIC Généralités.pdf
Cours de PIC Généralités.pdf
 

Traitement massif des données 2016

  • 1. INF442 : Traitement des Données Massives A1 : Introduction au calcul haute performance (HPC) suivi d’une introduction à C++ Frank Nielsen nielsen@lix.polytechnique.fr X2014 6 avril 2016 Frank Nielsen A1-1
  • 2. La mission du cours INF442 est de ... ◮ concevoir et analyser des algorithmes parallèles (//) sur des clusters de machines à mémoire distribuée ◮ implémenter ces algorithmes // en C++ avec le standard Message Passing Interface, MPI ◮ débogguer et exécuter ces programmes // sur un des quatres clusters en salles machines de l’X Frank Nielsen A1-2
  • 3. Objectifs du cours INF442 ◮ acquérir le “raisonnement informatique” pour le modèle de calcul parallèle sur mémoire distribuée = INF431 : multi-fils sur mémoire partagée ◮ programmer en C++ en utilisant l’interface MPI pour Message Passing Interface, et se servir d’un cluster de machines → 169 machines organisés en 4 clusters dans les salles informatiques ◮ se familiariser avec le monde du HPC et du Big Data et des sciences des données → 3A PA INFO : parcours HPC ou parcours Science des Données, etc. Frank Nielsen A1-3
  • 4. 6 avril Introduction au HPC et à C++ (pointeurs) TD : C++, passages par réf/pointeurs, unix command line 13 avril Clustering hiérarchique, C++ STL & récursivité TD : C++ STL, récursivité, regroupement hiérarchique 20 avril Introduction à MPI et topologie TD : k-moyennes et clustering d’images 27 avril —— vacances printemps : 25 au 29 avril —— 4 mai k-Moyennes et JL k-Moyennes TD : MPI 11 mai révisions PM, tri et MapReduce (culture) B5 : contrôle sur machine (PM) 18 mai classification (k-NN) détection de pourriels avec k-NN (avec MPI) 25 mai Algèbre linéaire et matrices matrices (regression) 1er juin Graphes et topologie/communication TD : topologie MPI (diffusion anneau/hypercube), graphes 8 juin contrôle classant (CC) Frank Nielsen A1-17
  • 6. Qu’est-ce que le Calcul Haute Performance, le HPC ? ◮ Sciences des super-ordinateurs (http://www.top500.org/) Top 1 : National Super Computer Center à Guangzhou, Chine : Tianhe-2 (MilkyWay-2) 3, 12 Millions de cœurs, 54, 9 Petaflops (1015, PFlops), 17, 8 Mega Watts, 1 MW = 100 e/h ∼ 1 Me/an ◮ mais auss green HPC évalue les performances en MFlops/Watt, http://www.green500.org/ ◮ Le HPC = domaine incluant paradigmes de programmation parallèle, langages de programmation, outils logiciels, systèmes informatiques, avec ses conférences dédiées (ACM/IEEE Super Computing), etc. Frank Nielsen A1-19
  • 7. HPC : le top 5 des super-ordinateurs dans le monde LINPACK benchmark : Rmax = performance maximale obtenue Rpeak = maximum théorique de performance. http://www.top500.org/project/top500_description/ Frank Nielsen A1-20
  • 8. En France, Total : Pangea SGI ICE X 2.3 PFlops (pétascale), 2015 Vous pouvez tous louer facilement et à faible coût du calcul HPC grâce aux services du cloud comme AMZ AWS, MS Azure, etc. Frank Nielsen A1-21
  • 9. Total en 2016 : Pangea SGI ICE X 6.7 PFlops (pétascale) stockage = 26 pétaoctets (≡ 6 millions de DVDs) Nombreuses applications (simulations) Frank Nielsen A1-22
  • 10. Aujourd’hui l’ère du pétascale et demain celle de l’exascale kiloFLOPS 103 megaFLOPS 106 gigaFLOPS 109 teraFLOPS 1012 petaFLOPS (PFLOPS, pétascale) 1015 exaFLOPS (EFLOPS, éxascale) 1018 zettaFLOPS 1021 yottaFLOPS 1024 ... ... googolFLOPS 10100 ... mais pas uniquement la puissance de calcul pour les Super-Ordinateurs : la mémoire (octets/bytes), la bande passante du réseau, etc. Le futur : exaFlops (1018 vers 2017-2020), zetaFlops (1021) vers 2030 ? Frank Nielsen A1-23
  • 11. Mais pourquoi donc faire du HPC ? Être plus efficace ! ◮ Aller plus vite et être plus précis ! (→ la météo) ◮ Résoudre de plus gros problèmes (→ simulation, → big data) ◮ Économiser de l’énergie ! À même puissance FLOPS utilisée, plus de processeurs lents qui consomment moins ! ◮ Simplifier des traitements de données : certains algorithmes sont intrinséquement parallèles vidéo/image : filtres foreach pixel/voxel, GPU & GPGPU ◮ Obtenir le résultat le plus rapidement possible en incluant le coût de développement ! → algorithmes parallèles plus faciles à implémenter qu’un code séquentiel optimisé plus difficile à développer (par des ingénieurs). Avoir la solution finale = implémenter un algorithme + exécuter cet algorithme. Frank Nielsen A1-24
  • 12. Le HPC en quelques images Frank Nielsen A1-25
  • 13. Cluster de machines (4 clusters en salles machines) m´emoire locale processeur m´emoire locale processeur m´emoire locale processeur m´emoire locale processeur m´emoire locale processeur m´emoire locale processeur r´eseau d’interconnexion ´echange de messages avec MPI Frank Nielsen A1-26
  • 14. Topologie des réseaux d’interconnexion dans un cluster Topologie (physique/virtuelle) importante pour le design des algorithmes parallèles. → Abstraction Comment faire une diffusion (broadcast) d’un nœud à tous les nœuds ? Frank Nielsen A1-27
  • 15. Évolution des processeurs Des architectures mono-processeurs aux machines multi-cœurs r´eseau ordinateur (CPU) carte m`ere carte m`ere CPU CPU CPU CPU cœur un seul socketsocket socket socketsocket 4 ordinateurs interconnect´es par un r´eseau une carte m`ere avec 4 processeurs un processeur quad-cœur ordinateur (CPU) ordinateur (CPU) ordinateur (CPU) cœur cœurcœur Pour passer à l’échelle, dans le calcul haute performance, il faut utiliser un cluster de machines Frank Nielsen A1-28
  • 16. Cluster moderne : machines hybrides/hétérogènes r´eseau d’interconnexion (topologie) nœud Central Processing Unit m´emoire nœud CPU CPU CPUCPU m´emoire ordinateur simple ordinateur quad processeurs ordinateur moderne: CPU multicœurs avec plusieurs cartes GPUs node cœur m´emoire GPU GPU C P U Grappe d’ordinateurs (computer cluster) cœur cœur cœur Comment programmer ces clusters hybrides et hétérogènes ? Frank Nielsen A1-29
  • 17. Cadre théorique idéal différent de la pratique mais utile ... ◮ Tâche (job) : un programme à exécuter qui donne lieu à un processus ◮ Ordonnanceur : gestionnaire des ressources qui choisit l’affectation des tâches (jobs) aux ressources du cluster (en salles info, SLURM) ◮ Cadre théorique pour ce cours lorsqu’on analyse un algorithme parallèle : un processus P tourne sur son propre processeur (un CPU mono-cœur) d’une machine qui constitue un nœud du cluster. ◮ En pratique : cluster hétérogène de machines (multi-cœurs, avec GPU). Plusieurs processus peuvent se retrouver mappés par l’ordonnanceur sur le même processeur (potentiellement sur le même cœur) Frank Nielsen A1-30
  • 18. HPC : granularité des calculs granularité = proportion des calculs (grains = calculs locaux) sur les communications (inter-processus). ≡ Fréquence des communications (ou synchronisation) entre les processus. ◮ grain fin (petit grain, fine-grained) : plein de petites tâches, données souvent transferées entre les processus après de petits calculs (ex., GPU). ◮ gros grain (coarse-grained) : les données ne sont pas échangées souvent et après des gros calculs. Cas extrême, embarrasingly parallel, très peu de communications. Frank Nielsen A1-31
  • 19. Deux notions en calcule parallèle : parallélisme et concurrence Parallélisme et concurrence : ◮ Parallélisme : tâches exécutées litéralement en même temps, (physiquement plusieurs unités de calcul) ◮ Concurrence : au moins deux tâches qui progressent conjointement dans le temps. Pas nécessairement en même temps (time-slicing sur un même CPU, multi-tâche sur un cœur) Frank Nielsen A1-32
  • 20. Modèles de programmation parallèle des nœuds ◮ Modèle de programmation vectorielle (SIMD, Cray) ◮ Modèle de programmation à mémoire distribuée : échanges de messages explicites → MPI (ici = INF442 !) ◮ Modèle de programmation à mémoire partagée : multi-threading (OpenMP), INF431 ◮ Modèle de programmation hybride : GPU, GPGPU pour certains calculs (CUDA, OpenCL, HMPP) GPGPU = General Purpose GPU ◮ Modèle de programmation mixte : Chaque processus MPI utilise plusieurs fils/threads (HPC geek !) ◮ Modèle de programmation mixte et hybride (MPI+fils+GPU, HPC gourou !) Frank Nielsen A1-33
  • 21. Les Grandes Données, le Big Data ... Traitement massif des données (HPC, gros grains), traitement des données massives (HPC, petits grains). BigData = un buzzword très médiatisé, renferme beaucoup de facettes, (large-scale) Les 4 V sur les données : ◮ Volume ◮ Variété (hétérogène) ◮ Vitesse (données générées en temps réel, capteurs) ◮ Valeur (pas de simulation mais de la valorisation) Frank Nielsen A1-34
  • 22. Tolérance aux pannes : un problème récurrent sur clusters Tolérance aux pannes des ordinateurs ?, des réseaux ?, des disques ?, etc. : ◮ MPI : zéro tolérance mais grande souplesse de programmation ◮ MapReduce (Hadoop) : grande tolérance mais modèle de calcul plus limité On peut faire du MapReduce (modèle de programmation //) avec MPI Frank Nielsen A1-35
  • 23. Quelques fausses idées sur les systèmes distribués ! 1. Le réseau est fiable 2. Le temps de latence est nul 3. La bande passante est infinie 4. Le réseau est sûr 5. La topologie du réseau ne change pas 6. Il y a un et un seul administrateur réseau 7. Le coût de transport est nul 8. Le réseau est homogène Frank Nielsen A1-36
  • 24. Introduction à C++ memento C++ sur moodle Frank Nielsen A1-37
  • 25. Le langage Orienté Objet (OO) C++ ◮ créé par Bjarne Stroustrup en 1983 ◮ Orienté Objet (OO) avec typage statique. à influencé Java et dérive de C (≈ 1970) ◮ Code compilé rapide (= Python interprété), pas de machines virtuelles (= Java) ◮ On gère soi-même la mémoire : pas de ramasse miette (garbage Collector, GC). Attention aux erreurs lors de l’exécution (system crash, segmentation fault, core dump) ◮ Passage par valeurs, pointeurs ou références (=Java : passage par valeur ou par référence pour les objets) ◮ Extensions de fichiers : .cc .cpp .cxx .c++ .h .hh .hpp .hxx .h++ ◮ Utilise g++ (GNU Compiler Collection) de la fondation GNU Frank Nielsen A1-38
  • 26. Le compilateur C++ (GNU) Standards (ANSI C++, C++11, etc.) et divers compilateurs [france ~]$ g++ --version g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2 -55) Copyright (C) 2006 Free Software Foundation , Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ⇒ existe de nombreuses versions de g++ (C++98, C++11 ; etc.)STL (Standard Template Librarry) par défaut dans C++98 Frank Nielsen A1-39
  • 27. Bienvenue en C++ // pour les entrées et sorties : #i n c l u d e <iostream > i n t main () { cout << " Bienvenue en INF442n" ; r e t u r n 0; // pas obligatoire } g++ bienvenue.cpp -o bienvenue bienvenue cout = c(onsole) out Frank Nielsen A1-40
  • 28. Bienvenue au C++ #i n c l u d e <iostream > // pour éviter décrire std : :cout using namespace std ; i n t promo=14; i n t main () { cout << " Bienvenue en INF442 X"<<promo<<endl ; /∗ cout = Standard output stream on ’ e c r i t dans l e f l o t avec l e s chevrons << ∗/ } Frank Nielsen A1-41
  • 29. Bienvenue au C++ : entrées et sorties #i n c l u d e <iostream > using namespace std ; i n t main () { i n t x ; cout << " Entrez un e n t i e r : " ; c i n >> x ; cout << "son c a r r e e s t : "<<x∗x<<endl ; } Et aussi cerr qui ne temporise pas et affiche immédiatement les messages importants (d’erreur) sur la console ... Frank Nielsen A1-42
  • 30. La mémoire vive : le ruban mémoire i n t p=2014; i n t ∗ ptrp = &p ; // un pointeur sur p cout<<" a d r e s s e de l a case var p : "<<ptrp<<endl ; (∗ ptrp ) = p+2; // on modifie le contenu de la case cout<<p<<endl ; 0xffffcc04 = &p 2014 0xffffcc04 &ptrp (adressage) contenu *ptrp (d´er´ef´erencement) &p : adressage, l’adresse de p ∗p : déréférencement, on accède au contenu de p (le contenu peut-être une adresse mémoire) Frank Nielsen A1-43
  • 31. Les pointeurs en C++ et le typage des variables ◮ Déclaration de pointeurs : int * ptr_entier, *ptr1, *ptr2; char * ptr_caractere; double * ptr_real; ◮ Opérateur de référence (adressage) : & int var=1; int *var2; // pointeur sur une variable de type entier var2=&var1; // var2 pointe sur var1 (alias) ◮ Opérateur de déréférencement : * /* prend l’entier contenu dans l’endroit memoire reference par var2 */ int var3=(*var2); Frank Nielsen A1-44
  • 32. C++ : les pointeurs en action ! i n c l u d e <iostream > using namespace std ; // pour les Entrées/Sorties i n t main () { i n t var1 =442; i n t ∗ var2 ; var2=&var1 ; // var2 pointe sur var1 cout<<" v a l e u r de var2 : "<<var2<<endl ; i n t var3 =(∗ var2 ) ; cout<<" v a l e u r de var3 : "<<var3<<endl ; r e t u r n 0; // fini sans le moindre probleme - :) } console> g++ programme.cpp -o monprogramme.exe console> monprogramme.exe Frank Nielsen A1-45
  • 33. Pourquoi manipuler des pointeurs ? Pointeur = variable qui sauvegarde la référence d’une autre variable. Valeur d’un pointeur = adresse mémoire i n t var1 =442; var2 = 2015; i n t ∗ Ptr1 , ∗ Ptr2 ; Ptr1 = &var1 ; Ptr2 = &var2 ; Facilite l’implémentation de structures de données dynamiques → listes chaînées, arbres, graphes, etc. En C++/C, les pointeurs permettent : ◮ d’allouer de la mémoire pour une variable en retournant un pointeur sur cette zone ◮ d’accéder à la valeur de la variable par déréférencement : *Ptr1 ◮ de libérer de la mémoire manuellement * : opérateur de déréférence = “ valeur pointée par ” Frank Nielsen A1-46
  • 34. Les références et les alias i n t val1 =442; i n t val2 =2016; // alias i n t & r e f V a l 1=val1 ; cout<< r e f V a l 1 <<endl ; //442 r e f V a l 1=val2 ; // ci-dessous, le phénomène d’alias cout<< val1 <<endl ; //2016 Frank Nielsen A1-47
  • 35. Sémantiques différentes déclaration/code La source de confusion (au début !) vient des sémantiques différentes ◮ Déclarations de variables : ◮ T* ptrVar : variable de type “pointeur sur type T” passée par valeur=adresse mémoire ◮ T& refVar : variable de type T passée par référence ◮ T*& refPtrVar : variable de type “pointeur sur type T” passée par référence ◮ Dans la partie instructions de code : ◮ &Var : retourne l’adresse utilisée pour stocker la valeur de Var ◮ *Var : si type de Var est “pointeur sur”, retourne la valeur stockée à l’adresse contenue dans Var (valeur de Var) Frank Nielsen A1-48
  • 36. #i n c l u d e <iostream > using namespace std ; i n t main () { i n t val1 = 2015 , val2 = 442; i n t ∗ p1 , ∗ p2 ; p1 = &val1 ; // p1 = adresse de val1 p2 = &val2 ; // p2 = adresse de val2 ∗p1 = 2016; // valeur pointée par p1 = 2016 ∗p2 = ∗p1 ; // valeur pointée par p2 = valeur pointée par p1 p1 = p2 ; // p1 = p2 (valeur du pointeur copiée) ∗p1 = 441; // valeur pointée par p1 = 441 cout << " val1=" << val1 << endl ; // affiche 2016 cout << " val2=" << val2 << endl ; // affiche 441 r e t u r n 0; } Frank Nielsen A1-49
  • 37. int val1 = 2015, val2 = 442; int * p1, * p2; p1 = &val1; // p1 = adresse de val1 p2 = &val2; // p2 = adresse de val2 *p1 = 2016; *p2 = *p1; &val2&val1 2016 2016 p1 p2 Frank Nielsen A1-50
  • 38. p1 = p2; &val2&val1 2016 2016 p1 p2 Frank Nielsen A1-51
  • 39. *p1 = 441; &val2&val1 2016 441 p1 p2 Frank Nielsen A1-52
  • 40. Les pointeurs de pointeurs Rappel : Pointeur = variable qui a comme valeur la référence mémoire d’une autre variable. double a ; double ∗ b ; double ∗∗ c ; double ∗∗∗ d ; a =3.14159265; b=&a ; c=&b ; d=&c ; cout<<b<<’ n ’<<c<<endl<<d<<endl ; Frank Nielsen A1-53
  • 41. Les pointeurs de pointeurs double a; double* b; double** c; double*** d; a=3.14; b=&a; c=&b; d=&c; a b c 3.14 0x22aac0 0x22aac0 0x22aab8 0x22aab8 0x22aab0 0x22aab0 &d d Frank Nielsen A1-54
  • 42. Le pointeur NULL NULL=0 ◮ utile dans la construction récursive de structures de données (listes, arbres, graphes, matrices creuses, etc.) ◮ ne pointe pas sur une référence valide or une adresse mémoire : double * ptr=NULL; ... else return new Noeud("feuille", NULL, NULL); ◮ attention aux segmentation faults : T ∗ ptr ; ptr=maFonctionSuper442 () ; cout<< (∗T)<<endl ; // peut exploser si T=NULL ici ! Frank Nielsen A1-55
  • 43. Passage par valeurs et passage par références void swap ( i n t& x , i n t& y ) // par référence { i n t temp = x ; x = y ; y = temp ;} void swapPtr ( i n t ∗ Ptr1 , i n t ∗ Ptr2 ) // Attention ! { i n t ∗ Ptr ; Ptr=Ptr1 ; Ptr1=Ptr2 ; Ptr2=Ptr ;} void swapGoodPtr ( i n t ∗ x , i n t ∗ y ) // ok ! { i n t temp = ∗x ; ∗x = ∗y ; ∗y = temp ;} i n t main () { i n t a = 2 , b = 3; swap ( a , b ) ; cout<<a<<" "<<b<<endl ; // OK a=2; b=3; i n t ∗ Ptra =&a ,∗ Ptrb =&b ; swapPtr ( Ptra , Ptrb ) ; cout<<∗Ptra<<" "<<∗Ptrb<<endl ; // non ! swapGoodPtr ( Ptra , Ptrb ) ; cout<<∗Ptra<<" "<<∗Ptrb<<endl ; // oui ! Frank Nielsen A1-56
  • 44. Pointeurs et références ◮ une référence est toujours définie, d’un type donné, et ne peux jamais changer. Pas d’arithmétique de références ni de coercion. ◮ en C++, passage par valeur ou par référence : Si la valeur est un pointeur, la fonction pourra changer le contenu des cases mémoires pointées, mais au retour de la fonction, les pointeurs arguments restent inchangés. ◮ Passage par référence ne copie pas l’objet sur la pile d’appel des fonctions : i n t fonctionPassageParRef ( MaClasse& c l a s s e O b j e t ) { . . . } Frank Nielsen A1-57
  • 45. Un mauvais exemple d’utilisation des références dangling reference i n t& v a r i a b l e L o c a l e () { i n t x=442; r e t u r n x ;} Ça compile avec un message d’alerte (warning) : In f u n c t i o n i n t& v a r i a b l e L o c a l e () : ptr12 . cpp : 5 : 6 : a t t e n t i o n : r e f e r e n c e to l o c a l v a r i a b l e x returned [−Wreturn−l o c a l −addr ] { i n t x=442; r e t u r n x ;} Pour transformer ces alertes en erreur de compilation, faire g++ -Werror man g++ pour le manuel Frank Nielsen A1-58
  • 46. Exercice : la fonction magique ! #i n c l u d e <s t d i o . h> i n t a = 23; i n t fonctionMagique ( i n t b , i n t ∗p1 , i n t ∗p2 , i n t x ) { i n t e ; e = 14; a = 15; x = 16; ∗p1 = 17; b = 18; p2 = &b ; ∗p2 = 19; r e t u r n b ; } i n t main () { i n t b = 10 , c = 11 , d = 12 , e = 13 , f ; f = fonctionMagique (b , &c , &d , a ) ; p r i n t f ( "%d t%d t%d t%d t%d t%dn" , a , b , c , d , e , f ) ; //ici syntaxe C // 15 10 17 12 13 19 Frank Nielsen A1-59
  • 47. Les tableaux en C++ : Allocation statique Les indices commencent à 0 comme pour Java, mais on ne peut pas faire tab.length ! int nombrePremiers [4] = { 2, 3, 5, 7 }; int baz [442] = { }; // valeurs initialisees a zero int matrice [3][5]; // 3 lignes 5 colonnes void procedure (int tableau[]) {} Après, on verra la classe vector de la STL ... Frank Nielsen A1-60
  • 48. #i n c l u d e <iostream > using namespace std ; i n t main () { i n t tab [ 5 ] ; i n t ∗ p ; p = tab ; ∗p = 10; p++; ∗p = 20; p = &tab [ 2 ] ; ∗p = 30; // arithmétique de pointeurs ! p = tab + 3; ∗p = 40; // arithmétique de pointeurs déréférencée ! p = tab ; ∗(p+4) = 50; f o r ( i n t n=0; n<5; n++) cout << tab [ n ] << " " ; r e t u r n 0;} // 10 20 30 40 50 Frank Nielsen A1-61
  • 49. Les pointeurs void Syntaxe : void *ptrVoid ◮ un type spécial de pointeurs : pointe sur une zone mémoire non typée ◮ pratique car on peut pointer sur n’ importe quel type de variable (int, int, char, string, T) ◮ ... mais on ne peut pas déférencer. Pour ce faire, on doit faire de la coercion ( type casting ) : T* ptrT=(T *)ptrVoid; double tabd [5]={1 ,2 ,3 ,4 ,5} , ∗ ptrd=tabd ; cerr << ∗( tabd+3)<<endl ; // affiche 4 char ∗ ptrc2=(char ∗) tabd ; void ∗ d= ( ptrc2+3∗ s i z e o f ( double ) ) ; cerr <<(∗(double ∗) (d) )<<endl ; // // affiche 4 Frank Nielsen A1-62
  • 50. Les tableaux : allocation dynamique en C++ On doit gérer l’espace mémoire soi-même en C++, et il faut donc libérer la mémoire quand on ne l’utilise plus . i n t t a i l l e =2015; i n t ∗ tab ; tab=new i n t [ t a i l l e ] ; // ... utilisez ce tableau puis LIBERER le ! d e l e t e [ ] tab ; Frank Nielsen A1-63
  • 51. Pointeurs et tableaux La valeur d’une variable tableau tab est l’adresse mémoire de son premier élément i n t tab [ 4 4 2 ] ; i n t ∗ ptr ; Le pointeur ptr est une variable qui stocke une adresse mémoire pour un int (4 octets = 32 bits, sur architecture 32 bits). On peut donc faire : ptr=tab ; Un tableau est considéré comme un pointeur constant . Il est donc interdit de faire : tab=ptr ; // pas autorisé Frank Nielsen A1-64
  • 52. Allocation des tableaux multi-dimensionnels #i n c l u d e <iostream > using namespace std ; i n t main ( i n t argc , char ∗ argv [ ] ) { double ∗∗ m a t r i c e T r i a n g u l a i r e ; i n t i , j , dimension =20; m a t r i c e T r i a n g u l a i r e=new double ∗[ dimension ] ; f o r ( i =0; i <dimension ; i++) m a t r i c e T r i a n g u l a i r e [ i ]=new double [ dimension ] ; f o r ( i =0; i <dimension ; i++) f o r ( j =0; j<=i ; j++) i f ( i==j ) m a t r i c e T r i a n g u l a i r e [ i ] [ j ]=1; e l s e m a t r i c e T r i a n g u l a i r e [ i ] [ j ]=0; Frank Nielsen A1-65
  • 53. int d=2015; double **T=new double*[d]; for(i=0;i<d;i++) T[i]=new double[d]; T T[0] T[d-1] T[1] T[0][0] T[1][0] T[1][1] T[d − 1][0] T[d − 1][1] T[d − 1][d − 1] pointeur sur un double* (type double**) T[i] pointeur sur un double (type double*) Frank Nielsen A1-66
  • 54. Libérer la mémoire des tableaux (multi-dimensionnels) ! #i n c l u d e <iostream > using namespace std ; i n t main ( i n t argc , char ∗ argv [ ] ) { double ∗∗ m a t r i c e T r i a n g u l a i r e ; i n t i , j , dimension =20; . . . f o r ( i =0; i <dimension ; i++){ f o r ( j =0; j<=i ; j++) {cout<<m a t r i c e T r i a n g u l a i r e [ i ] [ j ]<<" " ;} cout<<endl ; } . . . Frank Nielsen A1-67
  • 55. Les dangers des pointeurs : dangling pointer Un pointeur qui ne pointe sur rien : dangling pointer i n t main () { i n t ∗ arrayPtr1 ; i n t ∗ arrayPtr2 = new i n t [ 4 4 2 ] ; arrayPtr1 = arrayPtr2 ; d e l e t e [ ] arrayPtr2 ; // si on a de la chance quelque chose sinon // une segmentation fault, dépend du tas cout << arrayPtr1 [ 4 4 1 ] ; r e t u r n 0;} Nombreux effets de bords imprévisibles possibles : dépend de l’historique de l’utilisation du tas (heap) Frank Nielsen A1-68
  • 56. Les dangers des pointeurs : zones non-accessibles On peut réserver des zones mémoires qui ne seront plus accessibles : i n t ∗ Ptr1= 2015; i n t ∗ Ptr2 = 442; Ptr1 = Ptr2 ; Imaginez maintenant : i n t ∗ Ptr1= new i n t [ 2 0 1 5 ] ; i n t ∗ Ptr2 = 442; Ptr1 = Ptr2 ; out of memory ! Outil de visualisation dynamique et de suivi de la mémoire lors de l’exécution de programmes. http://valgrind.org/ Frank Nielsen A1-69
  • 57. Objets et méthodes en C++ Attention, il faut mettre un ; après la déclaration de classe (= Java) c l a s s Boite { p u b l i c : double h o r i z o n t a l ; // dimension largeur double v e r t i c a l ; /∗ dimension hauteur ∗/ }; i n t main ( ) { Boite B1 , B2 ; double s u r f a c e = 0 . 0 ; B1 . h o r i z o n t a l = 5 . 0 ; B1 . v e r t i c a l = 6 . 0 ; s u r f a c e = B1 . h o r i z o n t a l ∗ B1 . v e r t i c a l ; cout << " Surface de l a b o i t e B1 : " << s u r f a c e << endl ; r e t u r n 0;} Frank Nielsen A1-70
  • 58. Objets : constructeur(s) et destructeur ˜ en C++ Il peut y avoir plusieurs constructeurs mais toujours un seul destructeur. c l a s s Donnee { p u b l i c : i n t d ; double ∗ a t t r i b u t ; // constructeurs (plusieurs possibles) Donnee () {d=3; a t t r i b u t=new double [ d ] ; } Donnee ( i n t dd ) {d=dd ; a t t r i b u t=new double [ d ] ; } // destructeur : un seul ~Donnee () { d e l e t e [ ] a t t r i b u t ; cout<<" Destructeur appele "<<endl ;} }; i n t main () { i n t dim=500; Donnee ∗x=new Donnee ( dim ) ; d e l e t e x ; r e t u r n 0;} Frank Nielsen A1-71
  • 59. Hiérarchies de classes Utile lorsqu’on manipule des hiérarchies de classes, polymorphisme dynamique . double rand442 () { r e t u r n ( double ) rand () / RAND_MAX;} c l a s s Polygon { p u b l i c : i n t n ; s t r i n g name ; } ; c l a s s T r i a n g l e : p u b l i c Polygon { p u b l i c : T r i a n g l e () {n=3; name=" t r i a n g l e " ; } } ; c l a s s Carre : p u b l i c Polygon { p u b l i c : Carre () {n=4;name=" c a r r e " ; } } ; i n t main () { Polygon ∗ ptr ; srand ( time (NULL) ) ; i f ( rand442 () <0.5) ptr=new Carre () ; e l s e ptr=new T r i a n g l e () ; cout<<" cotes ="<< ptr−>n ; r e t u r n 0;} Frank Nielsen A1-72
  • 60. C++ : La surcharge d’opérateurs (overloading operators) Il est pratique de redéfinir certains opérateurs (comme +, /, =, etc.) en les surchargeant . Par exemple, redéfinir l’égalité pour un objet en recopiant tous les enregistrements (champs). c l a s s Complex { p u b l i c : Complex ( double re , double im ) : r e a l ( re ) , imag ( im ) {}; Complex operator +(const Complex& other ) ; Complex operator =(const Complex& other ) ; p r i v a t e : double real , imag ; } ; Complex Complex : : operator +(const Complex& other ) { double r e s u l t _ r e a l = r e a l + other . r e a l ; double result_imaginary = imag + other . imag ; r e t u r n Complex ( r e s u l t _ r e a l , result_imaginary ) ;} Frank Nielsen A1-73
  • 61. f r i e n d ostream &operator <<(ostream &out , Complex c ) //output { out<<" r e a l part : "<<c . real <<"n" ; out<<"imag part : "<<c . imag<<"n" ; r e t u r n out ; } f r i e n d istream &operator >>(istream &in , Complex &c ) //input { cout<<" enter r e a l part : n" ; in>>c . r e a l ; cout<<" enter imag part : n" ; in>>c . imag ; r e t u r n in ; } Complex a ( 2 . 1 , 3 . 2 ) , b ( 5 . 3 , 6 . 4 ) ; cout<<a<<b ; Frank Nielsen A1-74
  • 62. La généricité en C++ : les templates template <class T> void swap ( T& a, T& b ) {T c(a); a=b; b=c;} ◮ Notez que la classe T doit avoir un constructeur T(Tobject). ◮ Il faudra surcharger l’opérateur = Frank Nielsen A1-75
  • 63. La classe vector de la STL STL = Standard Template Library : formalisme hautement générique, container, iterator Container qui permet de gérer des tableaux de taille dynamique aisément. #i n c l u d e <vector > i n t s i z e = 442; // initialisation à 0 std : : vector <int > ar ra y ( s i z e ) ; // on peut rajouter dynamiquement des élèments f o r ( i n t i =0; i <2∗ s i z e ; ++i ) { a rr ay [ i ] = i ;} // pas besoin de delete http://www.cplusplus.com/reference/vector/vector/ http://www.cplusplus.com/reference/cstring/size_t/ Frank Nielsen A1-76
  • 64. Le mot clé const dans les méthodes const indique que l’on ne peut pas changer les variables de l’objet this c l a s s MaClasse{ i n t compteur =0; void Proc1 () { compteur++; // ça marche std : : cout << " Incremente " << std : : endl ; } void Proc2 () const {// cela ne compilera pas car on veut changer counter ! compteur++; std : : cout << " Incremente " << std : : endl ; } }; Frank Nielsen A1-77
  • 65. Quizz C++ void proc () { i n t ∗ tab ; tab=new i n t [ 2 0 1 4 ] ; // ... } Lors d’un appel à proc, le tableau tab est créé en mémoire : 1. dans la pile d’exécution 2. dans le tas Frank Nielsen A1-78
  • 66. Quizz C++ void proc () { i n t tab [ 2 0 1 4 ] ; // ... } Lors d’un appel à proc, le tableau tab est créé en mémoire : 1. dans la pile d’exécution 2. dans le tas Frank Nielsen A1-79
  • 67. Quizz C++ bool p a i r e ( i n t x ) { i f ( x=0) { r e t u r n true ;} e l s e { r e t u r n ! p a i r e ( x−1) ;} } i n t main () { p a i r e (5) ;} Que se passe t’il lorsqu’on appelle la fonction récursive paire(5) : 1. le programme retourne false 2. le programme retourne true 3. on obtient un message d’erreur Segmentation fault (core dumped) Frank Nielsen A1-80
  • 68. Quizz C++ c l a s s Tab{ p u b l i c : i n t n ; i n t ∗ e l ; Tab( i n t nb ) {n=nb ; e l=new i n t [ n ] ; } ~Tab () { cerr <<"T" ; i f ( e l != 0 ) d e l e t e [ ] e l ;} }; Tab∗ func () { Tab∗ T1=new Tab (5) ; } i n t main () {Tab ∗ t=func () ; r e t u r n 0; } Est-ce que le programme est correct ? 1. non 2. oui 3. oui, mais le tableau n’a pas été libéré : il manque delete t; Frank Nielsen A1-81
  • 69. Quizz C++ c l a s s Test { i n t value ; p u b l i c : Test ( i n t v = 0) { value = v ;} i n t getValue () const { r e t u r n value ;} i n t incGetValue () const { value++; r e t u r n value ;} }; i n t main () { Test t (20) ; std : : cout<<t . getValue ()<<std : : endl ; r e t u r n 0;} Est-ce que le programme se termine normalement ? 1. oui 2. non 3. le programme ne compile pas Frank Nielsen A1-82
  • 70. Quizz C++ #i n c l u d e <iostream > i n t main () { double a =0.00001 , b=88888, c ; c = ( ( a+b) ∗( a+b) − 2∗a∗b − b∗b ) / ( a∗a ) ; // mathématiquement, que vaut c ? std : : cout << c << std : : endl ; } Quelle est la valeur de c retourné par le programme ? 1. 1 2. une autre valeur (par exemple, 9536.74) 3. le programme ne compile pas ! Frank Nielsen A1-83
  • 71. TD 1 : Les fondamentaux du C++ Rien ne remplace l’expérience en programmation ... ◮ Quizz (5-15 minutes) ◮ Quelques commandes Unix ◮ Hello world ! ◮ Débugger un programme ◮ Echange par références ◮ Echange par pointeurs ◮ Transposition de matrices ◮ Multiplication de matrices Inscrivez vous au tutorat si vous en ressentez le besoin ! Frank Nielsen A1-84
  • 72. Entraînement au TD1 Petits exercices pour se préparer au TD de cet après-midi : ◮ créer une matrice diagonale ◮ imprimer sur la console une matrice ◮ créer une matrice symétrique Frank Nielsen A1-85
  • 73. #i n c l u d e <iostream > using namespace std ; // on ne connait pas la longueur de diag // donc on doit passer sa longueur en argument double ∗∗ diagMat ( i n t dim , double ∗ diag ) { i n t i , j ; double ∗∗ r e s ; r e s=new double ∗ [ dim ] ; f o r ( i =0; i <dim ; i++) { r e s [ i ]=new double [ dim ] ; } f o r ( i =0; i <dim ; i++) { f o r ( j =0; j<dim ; j++) { i f ( i==j ) r e s [ i ] [ i ]= diag [ i ] ; e l s e r e s [ i ] [ j ]=0;} } r e t u r n r e s ;} Frank Nielsen A1-86
  • 74. Procédure = fonction qui ne retourne rient (void) void printMat ( double ∗∗M, i n t dim ) { i n t i , j ; f o r ( i =0; i <dim ; i++) { f o r ( j =0; j<dim ; j++) {cout<<M[ i ] [ j ]<<" t " ;} cout<<endl ; } } i n t main () { double diag [3]={1 ,2 ,3}; double ∗∗ Mdiag ; Mdiag=diagMat (3 , diag ) ; printMat ( Mdiag , 3 ) ; r e t u r n 0; } Frank Nielsen A1-87
  • 75. Version plus ’geek’, déconseillée, mais qu’on retrouve dans des codes ... ← issus de la syntaxe C double ∗∗ diagMat ( i n t dim , double ∗ diag ) { i n t i , j ; double ∗∗ r e s ; // par default, les valeurs sont egales a zero r e s=new double ∗ [ dim ] ; f o r ( i =0; i <dim ; i++) r e s [ i ]=new double [ dim ] ; f o r ( i =0; i <dim ; i++) f o r ( j =0; j<dim ; j++) r e s [ i ] [ j ]=( ( i==j ) ? diag [ i ] : 0) ; r e t u r n r e s ; } Frank Nielsen A1-88
  • 76. #i n c l u d e <iostream > // pour drand48(), inclure #i n c l u d e <s t d l i b . h> using namespace std ; double ∗∗ symMat( i n t dim ) { i n t i , j ; double ∗∗ r e s ; r e s=new double ∗ [ dim ] ; f o r ( i =0; i <dim ; i++) r e s [ i ]=new double [ dim ] ; f o r ( i =0; i <dim ; i++) f o r ( j =0; j<=i ; j++) { r e s [ i ] [ j ]=drand48 () ; r e s [ j ] [ i ]= r e s [ i ] [ j ] ; } r e t u r n r e s ; } Frank Nielsen A1-89
  • 77. Déconseillé mais on peut réécrire ce code comme suit : double ∗∗ symMat( i n t dim ) { i n t i , j ; double ∗∗ r e s ; r e s=new double ∗ [ dim ] ; f o r ( i =0; i <dim ; i++) r e s [ i ]=new double [ dim ] ; f o r ( i =0; i <dim ; i++) f o r ( j =0; j<=i ; j++) { r e s [ i ] [ j ]= r e s [ j ] [ i ]=drand48 () ; // avant : res[i][j]=drand48() ;res[j][i]=res[i][j] ; } r e t u r n r e s ; } Frank Nielsen A1-90
  • 78. Petite introduction à Unix Frank Nielsen A1-91
  • 79. UNIX Unix est un système d’exploitation développé dans les années 1970 dans les laboratoires Bell Labs d’ AT&T par Ken Thompson et Dennis Ritchie. Frank Nielsen A1-92
  • 80. Commandes shell (Unix) ◮ Ouvrir une fenêtre shell (en salles machines, shell = bash) ◮ Lit le fichier de configuration initiale (= votre fichier .bashrc) dans votre répertoire “home” (˜). more .bashrc Modifier en utilisant un éditeur de texte (ou vi, emacs, ...) Puis relire la configuration à n’importe quel instant d’une session avec : source .bashrc Frank Nielsen A1-93
  • 81. Exemple de fichier .bashrc Pour les curieux : i f [ −f / e t c / b a s h r c ] ; then . / e t c / b a s h r c f i # Prompt PS1=" [ h W] $ " a l i a s rm=’rm −i ’ a l i a s cp=’cp −i ’ a l i a s mv=’mv −i ’ a l i a s mm=’/ u s r / l o c a l /openmpi −1.8.3/ b i n / mpic++ −I / u s r / l o c a l / boost −1.56.0/ i n c l u d e / −L/ u s r / l o c a l / boost −1.56.0/ l i b / −lboost_mpi −l b o o s t _ s e r i a l i z a t i o n ’ e x p o r t PATH=/u s r / l i b / openmpi /1.4− gcc / b i n : ${PATH} e x p o r t PATH=/u s r / l o c a l / boost −1.39.0/ i n c l u d e / boost −1_39 : ${PATH} LS_COLORS=’ d i =0;35 ’ ; e x p o r t LS_COLORS e x p o r t LD_LIBRARY_PATH=$LD_LIBRARY_PATH: / u s r / l o c a l /openmpi −1.8.3/ l i b / : / u s r / l o c a l / boost −1.56.0/ l i b / Frank Nielsen A1-94
  • 82. Quelques rudiments d’Unix ◮ Qui suis-je ? id [ f r a n c e ~] $ i d u i d =11234( f r a n k . n i e l s e n ) g i d =11000( p r o f s ) groups =11000( p r o f s ) ◮ Lister, renommer et effacer des fichiers : ls, mv (move) et rm (remove, option -i par défaut) ◮ Créer un fichier ou toucher à sa date : touch ◮ Visualiser et concatener des fichiers : more et cat more fichier Frank Nielsen A1-95
  • 83. Rudiments d’Unix Les Entrées/Sorties (E/Ss) et le pipe | [france ~]$ cat fichier1.cpp fichier2.cpp |wc 26 68 591 Manuel : [france ~]$ man wc Redirections : programme <input >output 2>error.log Frank Nielsen A1-96
  • 84. Rudiments d’Unix : les tâches (jobs) ◮ Lister les processus courants (leurs numéros, pid) : ps (avec options comme ps -a) ◮ Suspendre un processus avec Control-Z (Ctrl) sleep 10000 Ctrl-Z ◮ Place une tâche suspendue en processus de fond : bg ◮ Tuer des processus ou envoyer des signaux aux pids : kill [france ~]$ sleep 5000 & [1] 13728 [france ~]$ kill %1 [1]+ Terminated sleep 5000 Frank Nielsen A1-97
  • 85. Résumé ◮ le HPC sert à être plus efficace : plus vite, plus fines simulations, plus grandes données, etc. On peut simuler un ordinateur paralléle sur une machine séquentielle mais bien plus lent ! ◮ le C++ est un langage objet compilé, construit sur le langage C ◮ Unix est un système d’exploitation multi-tâches, ré-écrit en C Frank Nielsen A1-98
  • 86. Résumé des notions de C++ ◮ comprendre la mémoire locale (pile) et la mémoire globale (tas) ◮ passage par valeur, référence ou passage par pointeur des arguments ◮ allocation dynamique (new) et gestion manuelle de la mémoire (delete) ◮ classe et surcharge des opérateurs Frank Nielsen A1-99
  • 87. Résumé sur les pointeurs et références & : opérateur de référence = “ adresse de ” * : opérateur de déréférence = “ valeur pointée par ” ◮ pointeurs : les valeurs = adresses mémoires. Sauvegarde une référence sur une autre variable. ◮ pointeurs et tableaux (→ pointeurs constants), pointeurs de pointeurs, ... ◮ pointeurs void pointe sur n’importe quel type mais ne peut-être déréférencée (→ coercion, type casting) ◮ pointeurs NULL ◮ pointeurs et mémoire du tas : dangling pointers (mémoire désallouée → segmentation fault), plus accessible (garbage) ◮ références : utile pour le passage d’arguments aux fonctions. Pas d’arithmétique de références, de casting. Une référence ne change jamais et ne peut être NULL Frank Nielsen A1-100
  • 88. Sur le web ... https://www.lix.polytechnique.fr/~nielsen/HPC4DS/ Frank Nielsen A1-101
  • 89. INF442 : Traitement des Données Massives A2 : Le regroupement hiérarchique suivi d’une introduction à C++ STL Frank Nielsen nielsen@lix.polytechnique.fr X2014 13 avril 2016 Frank Nielsen A1-1
  • 90. Science des données : le clustering/regroupement Vision duale du cluster : ◮ Grouper en paquets (=clusters) homogènes les données ◮ Séparer les données en paquets distincts Frank Nielsen A1-3
  • 91. Le clustering/regroupement ◮ clusters linéairement séparables ◮ ou pas : → méthode à noyaux qui permet toujours de supposer la séparabilité linéaire en augmentant la dimension Frank Nielsen A1-4
  • 92. Clustering plat et clustering hiérarchique clustering plat clustering hiérarchique k-moyennes diagramme de Venn Frank Nielsen A1-5
  • 93. Le clustering : données en dimension > 3 Soupe de données, combien de catégories (= clusters) ? Comment visualiser les données de grandes dimensions (cartes SOMs, SNE) Frank Nielsen A1-6
  • 94. Le clustering hiérarchique ascendant On part des données X = {x1, ..., xn} qui sont des feuilles et on fusionne récursivement au fur et à mesure les sous-arbres jusqu’à ne plus qu’avoir un seul arbre. ascendant (feuilles → arbre) vs. descendant (arbre → feuilles) Frank Nielsen A1-7
  • 95. Le clustering hiérarchique ascendant (Vis. 2D) Frank Nielsen A1-8
  • 96. Le clustering hiérarchique ascendant (Iris 4D) Frank Nielsen A1-9
  • 97. Le clustering hiérarchique ascendant Plusieurs critères pour la fusion de deux sous-arbres dont les sous-ensembles de données Gi et Gj sont stockées dans leurs feuilles : ◮ stratégie du saut minimum : Single Linkage (SL) ∆(Xi , Xj ) = min xi ∈Xi ,xj ∈Xj D(xi , xj ) ◮ stratégie du saut maximum (ou diamètre) : Complete Linkage (CL) ∆(Xi , Xj ) = max xi ∈Xi ,xj ∈Xj D(xi , xj ) ◮ stratégie du saut moyen : Group Average (GA) ∆(Xi , Xj ) = 1 |Xi ||Xj | xi ∈Xi xj ∈Xj D(xi , xj ) Les feuilles initiales forment une forêt d’arbres à une feuille, puis on fait du chainage d’arbres en exactement n − 1 étapes... Hierarchical Cluster Analysis (HCA) : regroupement hiérarchique Frank Nielsen A1-10
  • 98. Les différents sauts illustrés Single Linkage SL (minimum distance) Complete Linkage CL, diameter Group Average GA, mean distance Frank Nielsen A1-11
  • 99. Le clustering hiérarchique I N F 4 4 2 I, N 4, 4 I, N, F 4, 4, 2 I,N,F,4,4,2 feuilles nœuds internes hauteur: nombre de fusions 0 1 2 3 Frank Nielsen A1-12
  • 100. Distance élémentaire entre deux données ∆(·, ·) (groupes) et D(·, ·) (éléments) ◮ Distance Euclidienne : DE (p, q) = d i=1(pi − qi )2) ◮ Distance de Manhattan (city block, L1) : D1(p, q) = d i=1 |pi − qi | ◮ Distance induite par une norme quelconque · : D(p, q) = p − q . Distance Lp : Dp(p, q) = d i=1 |pi − qi |p 1 p ◮ Distance de Mahalanobis : DΣ(p, q) = (p − q)⊤Σ−1(p − q) = DE (L⊤ p, L⊤ q), Σ−1 = L⊤L (décomposition de Cholesky). Σ est la matrice de covariance et Σ−1 la matrice de précision. Frank Nielsen A1-13
  • 101. Le clustering par agglomération ◮ Initialiser xi dans un cluster singleton Gi = {xi } ◮ Tant qu’il reste au moins deux clusters : ◮ Choisir Gi et Gj tel que ∆(Gi , Gj ) soit minimal ◮ Fusionner Gi,j = Gi ∪ Gj (ajouter Gi,j et retirer Gi et Gj ) ⇒ Exactement n − 1 étapes de fusion ⇒ Le résultat d’un regroupement hiérarchique est un dendrogramme. Différent d’un algorithme de partitionnement (clustering plat) comme les k-moyennes. Frank Nielsen A1-14
  • 103. Dendrogrammes et arbres philogénétiques Théorie de l’évolution → horloge Frank Nielsen A1-16
  • 104. Critère de fusion de Ward On fait intervenir les centroïdes des groupes ( = centre de masse) pour implanter un critère qui minimise la somme des variances des clusters. c(X′) est le centroïde du sous-ensemble X′ : c(X′) = 1 |X′| x∈X′ x Critère de Ward pour fusionner Gi (ni = |Gi |) avec Gj (nj = |Gj |) : ∆(Gi , Gj ) = ni nj ni + nj c(Gi ) − c(Gj ) 2 (di,j = xi − xj 2) → Très utilisé en pratique Frank Nielsen A1-17
  • 105. Critère de Ward et inversion ◮ similarité entre deux groupes S(Xi , Xj ) comme S(Xi , Xj ) = −∆(Xi , Xj ) ◮ opération de fusion est monotone si pour une séquence de fusion (chemin du dendrogramme) on a S1 ≥ S2 ≥ ... ≥ Sl . x3x2x1 S({x1, x2}, {x3}) x1 x2 x3 S({x1}, {x2}) → Inversion potentielle pour Ward, mais jamais pour les sauts minimum/moyen/maximum Variance S(X) = 1 n i (xi − ¯x) Frank Nielsen A1-18
  • 106. Dendrogramme : obtenir des partitions Deux coupes différentes donnent lieu à deux clusterings plats différents (partitions) Frank Nielsen A1-19
  • 107. Distances : métriques et ultramétriques Une distance d(·, ·) est : ◮ métrique si elle satisfait les trois axiomes : ◮ d(x, y) ≥ 0 avec égalité pour x = y seulement ◮ d(x, y) = d(y, x) symétrie ◮ d(x, y) ≤ d(x, z) + d(z, y), inégalité triangulaire ◮ ultramétrique si elle satisfait les axiomes : ◮ d(x, y) ≥ 0 avec égalité pour x = y seulement ◮ d(x, y) = d(y, x) symétrie ◮ d(x, y) ≤ max(d(x, z), d(z, y)) Frank Nielsen A1-20
  • 108. Distance et évolution Dans les arbres phylogénétiques, la distance entre deux espèces impose des restrictions sur la fonction distance : ◮ Arbre additif (additive tree) : poids sur chaque arête tel que pour chaque paire de feuilles, la distance est la somme des distances des arêtes les reliant. ◮ Arbre ultramétrique : Distances entre deux feuilles i et j et leur ancêtre commun k sont égales : di,k = dj,k. ◮ permet de définir une horloge globale : 1 2 di,j (hauteur) correspond au temps écoulé, Frank Nielsen A1-21
  • 109. Dendrogrammes et arbres philogénétiques horloge biologique, arbre ultramétrique Frank Nielsen A1-22
  • 110. Regroupement hiérarchique par l’algorithme UPGMA ◮ UPGMA : Unweighted Pair Group Method using arithmetic Averages ◮ Clustering avec saut moyen (= Average Linkage, AL) D(Gi , Gj ) = 1 ni nj xi ∈Gi xj ∈Gj d(xi , xj ) ◮ Si les données X sont accompagnées d’une matrice carrée des distances M = [Di,j ]i,j avec Di,j = D(xi , xj ) qui satisfait les propriétés ultramétriques, alors il existe un unique arbre ultramétrique qui peut être construit par l’algorithme UPGMA. Frank Nielsen A1-23
  • 111. Regroupement hiérarchique par UPGMA (résumé) ◮ Initialise xi a son cluster Ci et le positionne à hauteur 0. ◮ Tant qu’il reste plus de deux clusters : ◮ Trouver les clusters Ci et Cj qui ont la distance di,j minimale ◮ Définir un nouveau cluster Ck = Ci ∪ Cj et calculer la distance dk,l pour tout l ◮ Ajouter un nœud k avec les fils Ci et Cj et positionner le à hauteur 1 2 di,j ◮ Retirer Ci et Cj de la liste des clusters, et continuer jusqu’à temps d’obtenir la racine. ◮ Pour les deux derniers clusters Ci , and Cj , placer la racine à hauteur 1 2 D(Ci , Cj ). Frank Nielsen A1-24
  • 112. Les arbres : Rappel sur une implantation en Java Structure récursive (en C++, on utilise les pointeurs !) class BinaryTree <E> { E node; BinaryTree left ,right; BinaryTree(E v) {left=right=null; node=v;} BinaryTree(E v, BinaryTree l, BinaryTree r) {node=v; left=l;right=r;} } ... BinaryTree BT; BT=new BinaryTree (442 , new BinaryTree (421 , new BinaryTree (311 , null ,new BinaryTree (321)),new BinaryTree (431)),new BinaryTree (411)) ; ... Frank Nielsen A1-25
  • 113. Implantation en Java class BinaryTree <E> { ... String serialize (){String lefts ,rights; if (left == null) lefts="nil"; else lefts=left.serialize (); if (right == null) rights="nil"; else rights=right.serialize (); return "(node="+node+"("+lefts+","+rights+")"; } } ... System.out.println(BT.serialize ()); ... On ne gére pas la désallocation mémoire ... (en C++, on doit faire des delete Voyons voir en C++ comment implémenter ces structures de données grâce aux pointeurs ! Frank Nielsen A1-26
  • 114. Listes chaînées et arbres en C++ Frank Nielsen A1-27
  • 115. Dans le fichier IntList.h c l a s s I n t L i s t { p u b l i c : I n t L i s t ( i n t i , I n t L i s t ∗ next ) ; // constructeur ~ I n t L i s t () ; // destructeur void p r i n t () ; void p r i n t ( i n t t h r e s h o l d ) ; // elements > threshold I n t L i s t ∗ s u b L i s t ( i n t t h r e s h o l d ) ; // sous-liste elements > threshold p r i v a t e : // la cellule i n t i ; I n t L i s t ∗ next ; }; Frank Nielsen A1-28
  • 116. Dans le fichier IntList.cpp #i n c l u d e " I n t L i s t . h" #i n c l u d e <iostream > I n t L i s t : : I n t L i s t ( i n t i , I n t L i s t ∗ next ) { t h i s −>i = i ; t h i s −>next = next ; } I n t L i s t : : ~ I n t L i s t () {} void I n t L i s t : : p r i n t () { std : : cout << i << std : : endl ; i f ( next ) next−>p r i n t () ; } Frank Nielsen A1-29
  • 117. Dans le fichier IntList.cpp void I n t L i s t : : p r i n t ( i n t t h r e s h o l d ) { i f ( i >t h r e s h o l d ) std : : cout << i << std : : endl ; i f ( next ) next−>p r i n t ( t h r e s h o l d ) ; } I n t L i s t ∗ I n t L i s t : : s u b L i s t ( i n t t h r e s h o l d ) { I n t L i s t ∗ nextSubList = 0; i f ( next ) nextSubList = next−>s u b L i s t ( t h r e s h o l d ) ; i f ( i > t h r e s h o l d ) r e t u r n new I n t L i s t ( i , nextSubList ) ; r e t u r n nextSubList ; } Frank Nielsen A1-30
  • 118. #i n c l u d e " I n t L i s t . h" #i n c l u d e <iostream > i n t main () { I n t L i s t ∗ l i s t = new I n t L i s t (2 , new I n t L i s t (17 , new I n t L i s t (8 , new I n t L i s t (75 , new I n t L i s t (92 , 0) ) ) ) ) ; l i s t −>p r i n t () ; std : : cout << std : : endl ; Frank Nielsen A1-31
  • 119. #i n c l u d e " I n t L i s t . h" #i n c l u d e <iostream > i n t main () { I n t L i s t ∗ l i s t = new I n t L i s t (2 , new I n t L i s t (17 , new I n t L i s t (8 , new I n t L i s t (75 , new I n t L i s t (92 , 0) ) ) ) ) ; l i s t −>p r i n t () ; std : : cout << std : : endl ; Frank Nielsen A1-32
  • 120. Structure récursive d’arbres en C++ Dans le fichier tree.h (ou encore tree.hpp avec pp=++) c l a s s Tree { i n t key ; // The key Tree ∗ l e f t , ∗ r i g h t ; // The two subtrees (pointers !) p u b l i c : Tree ( i n t k , Tree ∗ l , Tree ∗ r ) ; ~Tree () ; // somme des entiers stockés aux nœuds i n t sumt () ; }; Frank Nielsen A1-33
  • 121. Dans le fichier tree.cpp Tree : : ~ Tree () { cerr <<" . "<<endl ; i f ( l e f t ) d e l e t e l e f t ; i f ( r i g h t ) d e l e t e r i g h t ; } Tree : : Tree ( i n t k , Tree ∗ l , Tree ∗ r ) { key=k ; l e f t=l ; r i g h t=r ;} i n t Tree : : sumt () { i n t r e s=key ; i f ( l e f t ) r e s+=l e f t −>sumt () ; i f ( r i g h t ) r e s+=right −>sumt () ; r e t u r n r e s ;} Frank Nielsen A1-34
  • 122. Dans le fichier main.cpp #i n c l u d e <iostream > #i n c l u d e " t r e e . h" using namespace std ; i n t main ( i n t argc , char ∗∗ argv ) { Tree ∗ l =new Tree (3 ,NULL,NULL) ; Tree ∗ r =new Tree (2 ,NULL,NULL) ; Tree ∗ r a c i n e = new Tree (6 , l , r ) ; cout << racine −>sumt () ; d e l e t e r a c i n e ; r e t u r n 0; On trouve 11 et trois petits points affichés sur la console Frank Nielsen A1-35
  • 123. La bibliothèque C++ STL : généricité Frank Nielsen A1-36
  • 124. Les classes génériques en C++ But de la généricité = produire du code indépendant des types (instanciés lors de l’usage) : // returns 0 if equal, 1 if value1 is bigger, -1 otherwise i n t compare ( const i n t &value1 , const i n t &value2 ) { i f ( value1 < value2 ) r e t u r n −1; i f ( value2 < value1 ) r e t u r n 1; r e t u r n 0; } // returns 0 if equal, 1 if value1 is bigger, -1 otherwise i n t compare ( const s t r i n g &value1 , const s t r i n g &value2 ) { i f ( value1 < value2 ) r e t u r n −1; i f ( value2 < value1 ) r e t u r n 1; r e t u r n 0;} ⇒ factorisation du code puis à la compilation, code polymorphique pour les divers types requis : génération des codes spécifiques pour les types demandés. Frank Nielsen A1-37
  • 125. #i n c l u d e <iostream > #i n c l u d e <s t r i n g > // returns 0 if equal, 1 if value1 is bigger, -1 otherwise template <c l a s s T> i n t compare ( const T &value1 , const T &value2 ) { i f ( value1 < value2 ) r e t u r n −1; i f ( value2 < value1 ) r e t u r n 1; r e t u r n 0; } // On est gentil ici pour le compilateur : // on indique explicitement les types demandés i n t main ( i n t argc , char ∗∗ argv ) { std : : s t r i n g h( " h e l l o " ) , w( " world " ) ; std : : cout << compare<std : : s t r i n g >(h , w) << std : : endl ; std : : cout << compare<int >(10 , 20) << std : : endl ; std : : cout << compare<double >(50.5 , 50.6) << std : : endl ; r e t u r n 0;} Frank Nielsen A1-38
  • 126. Inférence des types demandés par le compilateur #i n c l u d e <iostream > #i n c l u d e <s t r i n g > // returns 0 if equal, 1 if value1 is bigger, -1 otherwise template <c l a s s T> i n t compare ( const T &value1 , const T &value2 ) { i f ( value1 < value2 ) r e t u r n −1; i f ( value2 < value1 ) r e t u r n 1; r e t u r n 0; } // Le compilateur doit trouver le type demande ici : // inférence de types i n t main ( i n t argc , char ∗∗ argv ) { std : : s t r i n g h( " h e l l o " ) , w( " world " ) ; std : : cout << compare (h , w) << std : : endl ; std : : cout << compare (10 , 20) << std : : endl ; std : : cout << compare (50.5 , 50.6) << std : : endl ; r e t u r n 0;} Frank Nielsen A1-39
  • 127. Mécanisme de compilation et templates ◮ le compilateur ne génére pas de code directement lorsqu’il rencontre une classe/fonction template parce qu’il ne connaît pas encore quelles seront les types demandés. ◮ quand le compilateur rencontre une fonction template utilisée, il sait quel type est demandé : Il instancie alors le template et compile le code correspondant ⇒ les classes/fonctions templates doivent donc se trouver dans le fichier d’en-tête, header .h Le mécanisme de template ressemble donc a une macro expansion ... Frank Nielsen A1-40
  • 128. fichier compare.h : #i f n d e f COMPARE_H #d e f i n e COMPARE_H template <c l a s s T> i n t comp( const T& a , const T& b) { i f ( a < b) r e t u r n −1; i f (b < a ) r e t u r n 1; r e t u r n 0;} #e n d i f // COMPARE_H fichier main.cpp : #i n c l u d e <iostream > #i n c l u d e "compare . h" using namespace std ; i n t main ( i n t argc , char ∗∗ argv ) { cout << comp<int >(10 , 20) ; cout << endl ; r e t u r n 0; } Frank Nielsen A1-41
  • 129. Lire un fichier dans un vector de la STL Utiliser la classe vector de la STL pour les tableaux dynamiques ! i f s t r e a m f i n ; f i n . open ( " f i c h i e r . t x t " ) ; vector <s t r i n g > t e x t e ; s t r i n g mote ; while ( f i n >> mot) { t e x t e . push_back (mot) ;} f i n . c l o s e ( ) ; ◮ La boucle while lit jusqu’à temps de rencontrer EOF (End Of File) ◮ Les données sont des chaînes de caractères séparées par des délimiteurs (espace, tab, retour à la ligne, point virgule pour les fichiers CSV, Comma-Separated Values) Frank Nielsen A1-42
  • 130. STL : une collection de structures de données Le concept fondamental est le containeur avec son iterator , le tout en template ! Structure de données nom STL #include tableau dynamique vector <vector> liste chaînée list <list> pile stack <stack> file queue <queue> arbre binaire set <set> table de hachage unordered_map <set> arbre binaire map <set> tas ordonné file de priorité <queue> Classes STL = structures de données abstraites (interfaces standardisées) Les #include sont à faire sans le .h Frank Nielsen A1-43
  • 131. La STL : structures de données génériques set <s t r i n g > mots ; l i s t <Eleve> PromoX2014 ; stack < vector <int > > nombres ; À chaque container STL, on a un itérateur (iterator) associé de type container<T>::iterator set <s t r i n g >:: i t e r a t o r p=mots . f i n d ( " cours " ) ; l i s t <Eleve >:: i t e r a t o r premier=PromoX2014 . begin () ; stack < vector <int > >:: i t e r a t o r f i n=nombres . end () ; On déreférence un itérateur comme pour un pointeur : *it Frank Nielsen A1-44
  • 132. Les containeurs stockent par valeur, pas par reférence ◮ quand on insére un objet, le containeur va en faire une copie ◮ quand le containeur doit réarranger les objets, il procéde en faisant des copies de ceux-ci. Par exemple, si on tri, ou si on insére sur un containeur map, etc. ◮ si on veut éviter cela, il faudra donc faire des containeurs de pointeurs ! C++11 a le mot clef auto pour inférer directemement les types et un “foreach” (pour les curieux !) : f o r ( vector <Printer >:: i t e r a t o r i t = vec . begin () ; i t < vec . end () ; i t ++) { cout << ∗ i t << endl ; } f o r ( auto i t = vec . begin () ; i t < vec . end () ; i t ++) { cout << ∗ i t << endl ; } Frank Nielsen A1-45
  • 133. Fonctions membres communes à la STL Toutes les classes containeurs ont les fonctions membres : i n t s i z e () i t e r a t o r begin () i t e r a t o r end () bool empty () Pour lister tous les éléments d’un containeur, on fait : l i s t <s t r i n g >:: i t e r a t o r i t=maListe . begin () ; while ( i t != maListe . end () ) { cout << ∗ i t <<endl ; i t e r ++;} Notons que end() est un élément sentinel . On ne peut pas déreférencer end(). Frank Nielsen A1-46
  • 134. Différents accès aux éléments d’un containeur ◮ pour vector, on peut accéder aux éléments en utilisant un index [i] : vector <int > vec442 ; vec442 [0]=280; ... mais les crochets ne peuvent pas être utilisés pour list<int> par exemple ◮ on peut rajouter un élément à la fin d’une liste ou d’un vecteur avec push_back : monVecteur . push_back (2013) ; maListe . push_back (2013) ; ... mais il n’ y a pas de push_back pour les ensembles (codés par des arbres binaires) : set <int > monEnsemble ; monEnsemble . push_back (2013) ; // Erreur ! ! ! Frank Nielsen A1-47
  • 135. La liste (doublement chaînée) On peut ajouter à la tête ou à la queue d’une liste en temps constant : maListe . push_back (2013) ; maListe . push_front (2015) ; On peut insérer ou supprimer un élément avec un itérateur : l i s t <s t r i n g >:: i t e r a t o r p=maListe . begin () ; p=maListe . e r a s e (p) ; p=maListe . i n s e r t (p , "HPC" ) ; On peut avancer ou reculer dans une liste avec les opérateurs unaires ++ et -- : p++; p−−; // faire attention aux débordements possibles Seul bémol : on ne peut pas directement accéder i-ième élément (cela demande de parcourir la liste, pas de crochets). Frank Nielsen A1-48
  • 136. La liste doublement chaînée en STL : itérateurs Voir INF311/INF411 NULL NULL C++ HPC MPI list<string>::iterator it=liste.find("HPC") q=it-- q=it++ Frank Nielsen A1-49
  • 137. Les piles et les files ◮ Piles ( stacks ) et files ( queues ) sont des sous-classes de la classe deque ◮ Une pile est une liste chaînée avec la propriété Dernier Arrivé Premier Sorti, DAPS (LIFO : Last In First Out). ◮ Une file est une liste chaînée avec la propriété Premier Arrivé Premier Sorti, PAPS (FIFO : First In First Out). ◮ On accéde au dernier élèement au sommet de la pile ou au premier élément d’une file avec les primitives push et pop ◮ Pour les piles, on a aussi top, et pour les files front et back Frank Nielsen A1-50
  • 138. Les files de priorité On doit définir un operator < . La plus grande valeur est sur le haut (max-heap, top). priority_queue <int > Q; Q. push (23) ; Q. push (12) ; Q. push (71) ; Q. push (2) ; cout << Q. top () ; Q. pop () ; cout << Q. top () ; pour la plus petite valeur (min-heap), il faut donc changer le sens sémantique de l’opérateur < ... http://en.cppreference.com/w/cpp/language/operator_comparison Frank Nielsen A1-51
  • 139. On peut trier facilement avec une file de priorité... #i n c l u d e <queue> #i n c l u d e <iostream > using namespace std ; s t r u c t comparator { bool operator () ( i n t i , i n t j ) { r e t u r n i < j ;} }; i n t main ( i n t argc , char const ∗ argv [ ] ) { priority_queue <int , std : : vector <int >, comparator> minHeap ; minHeap . push (10) ; minHeap . push (5) ; minHeap . push (12) ; minHeap . push (3) ; minHeap . push (3) ; minHeap . push (4) ; while ( ! minHeap . empty () ) { cout << minHeap . top () << " " ; minHeap . pop () ; } r e t u r n 0;} // 12 10 5 4 3 3Frank Nielsen A1-52
  • 140. Les ensembles : set (arbres binaires équilibrés) On doit définir operator <. Toutes les valeurs sont uniques (sinon, utiliser un multiset). insert(value), erase(value), erase(iterator), iterator find(value) set <s t r i n g > s ; s . i n s e r t ( " Ecole " ) ; s . i n s e r t ( " Polytechnique " ) ; s . e r a s e ( " Ecole " ) ; cout << ∗( s . f i n d ( " Polytechnique " ) ) ; Frank Nielsen A1-53
  • 141. Le hachage (map) ◮ Différence entre hachage fermé (tableau) et hachage ouvert (tableau de pointeurs sur des listes). ◮ Templates pour la clef et le type de données map<K,T>. ◮ On doit définir operator < de comparaison pour le type K. map<int , s t r i n g > monHachage ; monHachage [23121981] = " A n n i v e r s a i r e Toto" ; monHachage [05031953] = " A n n i v e r s a i r e T i t i " ; . . . map<s t r i n g , int > monHachageRev ; monHachageRev [ "Toto" ] = 23121981; monHachageRev [ " T i t i " ] = 05031953; Frank Nielsen A1-54
  • 142. Le hachage (map) Les fonctions membres pour la classe STL map : erase(iterator), erase(K clef), map_name(K key) map<s t r i n g , int > M; M[ "A" ] = 23; M[ "B" ] = 12; M[ "C" ] = 71; M[ "D" ] = 5; M. e r a s e ( "D" ) ; cout << M[ "B" ] ; Frank Nielsen A1-55
  • 143. La classe STL paire à la rescousse map<s t r i n g , int > maMap; pair <s t r i n g , int > p a i r e ( "Tutu" , 606) ; maMap. i n s e r t ( p a i r e ) ; . . . // on créé un nouvel enregistrement en faisant aussi : maMap[ "Tata" ] = 707; ⇒ opérateur crochet [K] Frank Nielsen A1-56
  • 144. Les temps d’accés aux structures de données Pour un containeur à n éléments : vecteur list set map∗ Insérer/supprimer O(n) O(1) O(log n) ˜O(log n) Rechercher O(n) O(n) O(log n) ˜O(log n) map : implémentées historiquement avec des arbres binaires équilibrés (red-black trees). Minimise le pire des temps ! unordered_map : implémentées avec des fonctions de hachage (temps amorti en O(1)) Voir INF311/INF411. Frank Nielsen A1-57
  • 145. Les itérateurs Chaque containeur est equipé d’un itérateur : container <T>:: i t e r a t o r i t ; i t=C. begin () ; ◮ ++ et – pour avancer ou reculer ◮ * pour déreférencer ◮ == et =! pour les tests de comparaisons Seulement dans la classe vector, on peut bouger de p éléments (arithmétique) en faisant vector <T>:: i t e r a t o r i t ; i t=i t+p ; i t=i t −p ; Frank Nielsen A1-58
  • 146. Les itérateurs : premier et dernier éléments Le dernier élément est une sentinelle : cout << ∗(L . begin () ) ; // oui, si pas vide ! cout << ∗(L . end () ) ; // toujours non ! l i s t <s t r i n g >:: i t e r a t o r p = L . end () ; p−−; cout << ∗p ; // ok, si pas vide ! Frank Nielsen A1-59
  • 147. Compiler des programmes avec un Makefile Frank Nielsen A1-60
  • 148. Compiler un programme Exemple avec la fonction main dans le fichier main.cpp : g++ -Wall -o monProg442.exe fonctions.cpp main.cpp Les fichiers d’en-têtes (headers) en .h (templates) sont inclus dans les .cpp et lus lors de la compilation de fichiers .cpp Plus le programme (= ensemble de fichiers) devient gros, plus la ligne de compilation devient grande à taper : g++ -Wall -o monProg442.exe main.cpp fichier1. cpp fichier2.cpp fichier3.cpp Compilation avec l’option de débogage (option/ flag ’-g’) puis exécution dans un déboggeur. Quand le programme crashe, il écrit un fichier core puis débogage avec gdb, ou dans un IDE (Eclipse) Que faire lorsqu’on a de nombreux fichiers à gèrer dans un projet ? Frank Nielsen A1-61
  • 149. Compilation dans un fichier compilé objet : les .o Attention : ici objet n’a pas le sens de OO (orienté objet) ! g++ -c fichier.cpp produit un fichier fichier.o Dépend de l’architecture où a lieu la compilation : x86 32-bits ou 64-bits, Oracle Sparc, MacOS, etc. Par exemple, si vous compilez sous Windows, votre .o ne sera pas utilisable en salles machines (UNIX). C’est une grande différence avec Java qui compile en .class qui marche pour la JVM (Java Virtual Machine), donc partout où on a une JVM ! Frank Nielsen A1-62
  • 150. Graphe de dépendances d’un programme Projet Programme donnee.o main.o lecture.o donnee.cpp donnee.h main.cpp lecture.h lecture.cpp Comment faire pour recompiler si on a touché seulement au fichier donnee.cpp ? Doit-on recompiler lecture.cpp en lecture.o ? Frank Nielsen A1-63
  • 151. L’utilitaire UNIX make ◮ utilitaire pour compiler ( building ) des programmes exécutables, des bibliothèques, etc. ◮ organise les compilations, n’est pas spécifique à un langage donné ◮ utilise un script en entrée : Makefile ◮ on veut compiler un ensemble de cibles à partir de fichiers sources correspondants La commande touch permet de modifier les dates de dernière modification des fichiers. Pour forcer la recompilation : touch * ; make Frank Nielsen A1-64
  • 152. Les règles dans un Makefile Les commandes doivent suivre une tabulation (pas des espaces !) : target : source1 source2 ... sourceN commande1 commande2 ... Exemple : monProg : fichier1.cpp fichier2.cpp main.cpp g++ -o monProg fichier1.cpp fichier2.cpp main.cpp Puis make target, par exemple : make monProg Frank Nielsen A1-65
  • 153. Règle sans sources On nettoie tous les fichiers : clean : rm fichier1.o fichier2.o fichier3.o monProg puis par exemple ... make clean Frank Nielsen A1-66
  • 154. Règle sans commandes all: monProg monProg2 monProg: file1.o file2.o file3.o gcc -g -Wall -o myprog file1.o file2.o file3 .o monProg2: file4.c gcc -g -Wall -o myprog2 file4.c Il suffit alors de faire make all Frank Nielsen A1-67
  • 155. Un aperçu du TD2 Frank Nielsen A1-68
  • 156. Le TD2 : objets en C++ et récursivité ◮ nombres complexes C : constructeur, affichage, calcul du module ◮ quad-trees et requêtes géométriques Frank Nielsen A1-69
  • 157. Accès aux membres : o.v et ptro->v #i n c l u d e <iostream > #i n c l u d e <math . h> using namespace std ; c l a s s monome { p u b l i c : i n t d ; monome( i n t dd ) : d( dd ) {} double e v a l ( double x ) { r e t u r n pow( x , d) ;} }; i n t main () {monome m(3) ; monome ∗ ptrm=&m; cout<<m. e v a l (2)<<" "<<ptrm−>e v a l (3)<< endl ; cout<<m. d<<" " <<ptrm−>d<<endl ; r e t u r n 1; } Frank Nielsen A1-70
  • 158. Le TD2 : quad-trees en 2D Representation compacte d’une image binaire Frank Nielsen A1-71
  • 159. Octrees en 3D Frank Nielsen A1-72
  • 160. Octrees en infographie (proxy géométrique) Frank Nielsen A1-73
  • 161. Les trois concepts fondamentaux d’Unix Frank Nielsen A1-74
  • 162. Trois concepts Unix ◮ Les tâches et signaux : ps, kill, sleep 500 &, Control-Z : interruption , bg, fg ◮ Les entrées et sorties et opérateurs de redirection : monprog <input.txt >output.txt » pour rajouter (append) command > /dev/null 2>&1 ◮ Les commandes pipelinées : Compte le nombre de lignes des fichiers concaténés cat fichier1 fichier2 fichier3 | wc -l Frank Nielsen A1-75
  • 163. Les redirections 0 = STDIN, 1 = STDOUT, 2 = STDERR pgm > file Output of pgm is redirected to file pgm < file Program pgm reads its input from file pgm » file Output of pgm is appended to file n > file Output from stream with descriptor n redirected to file n » file Output from stream with descriptor n appended to file n >& m Merge output from stream n with stream m n <& m Merge input from stream n with stream m « tag Standard input comes from here through next tag at start of line Frank Nielsen A1-76
  • 164. Résumé la clustering hiérarchique (distance de base, distance d’ensembles) structures récursives en C++ la généricité avec la bibliothèque C++ STL : la classe vector // containeur list<Eleve> PromoX2014; // iterateur pour le containeur list<Eleve>::iterator el=PromoX2014.begin(); // on dereference pour obtenir l’element cout << (*el) <<endl; // on incremente pour aller a l’element suivant el++; écrire un Makefile trois concepts fondamentaux d’Unix Frank Nielsen A1-77
  • 165. Dendrogramme et partitionnement Partition en 4 clusters à partir du dendrogramme. Choisir une coupe (par forcément de hauteur constante). Frank Nielsen A1-78
  • 166. Dendrogramme : iris (4D) Graphique d’un arbre binaire où la hauteur d’une branche est proportionnelle à la distance entre les deux objets regroupés. Frank Nielsen A1-79
  • 167. Le clustering hiérarchique : single linkage (SL) Saut minimum D(Gi , Gj ) = min xi ∈Gi ,xj ∈Gj d(xi , xj ) Répeter tant que toutes les données xi ne soient pas contenues dans un seul cluster. À chaque instant tous les sous-arbres forment une forêt (partitition de X). n − 1 étapes de fusion : ◮ Problème (artefact) de chainage dans le clustering final. ◮ Complexité : naïf O(n3), algorithme SLINK en O(n2). Frank Nielsen A1-80
  • 168. Le clustering hiérarchique : saut maximum/saut moyen : ◮ Complete linkage (CL) : CLINK in O(n2) (1977) D(Gi , Gj ) = max xi ∈Gi ,xj ∈Gj d(xi , xj ) → très sensibles aux outliers, les artefacts de données ◮ Average linkage (AL) : O(n2) (1984) D(Gi , Gj ) = 1 ni nj xi ∈Gi xj ∈Gj d(xi , xj ) Même complexité en temps quadratique pour les sauts minimum/moyen/maximum Frank Nielsen A1-81
  • 169. Les piles : illustration stack <s t r i n g > S ; S . push ( "A" ) ; S . push ( "B" ) ; S . push ( "C" ) ; S . pop () ; Q. pop () ; S . push ( "D" ) ; Q. push ( "D" ) ; cout << S . top () ; Frank Nielsen A1-82
  • 170. Les files : illustration queue<s t r i n g > Q; Q. push ( "A" ) ; Q. push ( "B" ) ; Q. push ( "C" ) ; Q. pop () ; Q. push ( "D" ) ; cout << Q. f r o n t () << Q. back () ; Frank Nielsen A1-83
  • 171. La classe STL algorithm Procédures (pas des méthodes de classe) : find, remove, count, shuffle, replace, sort, for_each, min_element, binary_search, transform, copy, swap : i t e r = f i n d (L . begin () , L . end () , " Cours INF442" ) ; i n t x = count (L . begin () , L . end () , " i n s c r i t en INF442" ) ; r e p l a c e (L . begin () , L . end () , "DEP442" , "INF442" ) ; _if : prend une fonction booléene utilisateur : r e p l a c e _ i f (L . begin , L . end () , appartient442S , " Tutorat ") ; Frank Nielsen A1-84
  • 172. Édition de liens : linking Édition de liens = phase finale de la compilation. Rassemble tous les fichiers objets .o et produit un fichier exécutable. Les fichiers objets utilisés proviennent de : ◮ de la compilation de fichiers .cpp (.cpp g++ -c −−−−→ .o) ◮ de la bibliothèque standard (fonctions E/Ss, fonctions mathématiques log, exp, etc.) ◮ de bibliothèques extérieures (comme CImg lors du TD5) g++ fichier1.o fichier2.o main.o -o monProg442.exe - lpthread -lX11 Différence entre une bibliothèque statique .a (Unix, archive) .lib (Windows) et une bibliothèque dynamique .so (Unix, shared objects) .dll (Windows, dynamic linked library) Frank Nielsen A1-85
  • 173. Édition de liens : la commande ldd ldd : print shared library dependencies (Linux) #include <iostream > using namespace std ; i n t main () { cout << "J ’ u t i l i s e un cout ! " ; r e t u r n 0;} ldd programme.exe linux -gate.so.1 => (0 x00142000) libstdc ++.so.6 => /usr/lib/libstdc ++.so.6 (0 x008f8000) libm.so.6 => /lib/libm.so.6 (0 x0063c000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0 x008cc000) libc.so.6 => /lib/libc.so.6 (0 x004de000) /lib/ld -linux.so.2 (0 x004bf000) Frank Nielsen A1-86
  • 174. Les variables dans un Makefile ◮ déclaration d’une variable : NOM = valeur ◮ utilisation d’une variable : $(NOM) Par exemple, OBJFILES = file1.o file2.o file3.o PROGRAM = myprog $(PROGRAM): $(OBJFILES) gcc -g -Wall -o $(PROGRAM) $(OBJFILES) clean: rm $(OBJFILES) $(PROGRAM) Frank Nielsen A1-87
  • 175. Makefile : partie générique Idéalement, on aimerait paramétrer pour un ensemble d’architectures (UNIX/Windows/MacOS/Sparc, etc.). Pour chaque architecture, le nom du compilateur et ses options peuvent changer ... CC = g++ CCFLAGS = -g -Wall OBJFILES = file1.o file2.o file3.o PROGRAM = myprog $(PROGRAM): $(OBJFILES) $(CC) $(CCFLAGS) -o $(PROGRAM) $(OBJFILES) Bien d’autres possibilités plus étendues avec le Makefile Frank Nielsen A1-88
  • 176. Makefile : partie générique ◮ $@ : le fichier target courant ◮ $^ : la liste de tous les fichiers sources ◮ $< : la source la plus à gauche pour la cible courante myprog: file1.o file2.o file3.o gcc $(CCFLAGS) -o $@ $^ file1.o: file1.c file1.h file2.h gcc $(CCFLAGS) -c $< Frank Nielsen A1-89
  • 177. Makefile : partie générique BIN = JL_kmeans OBJS = randomsample.o mathtools.o partition.o FLAGS = -O3 INCLUDE = -I/usr/local/CImg -1.6.2/ LIBS = -L/usr/local/boost -1.58.0/ lib/ LDPATH = LD_LIBRARY_PATH =/usr/local/boost -1.58.0/ lib :/usr/lib/alliance/lib # exercice 0 cimgvec: cimgvec.cxx Makefile $(CXX) $(FLAGS) $(INCLUDE) -o $@ $@.cxx $( LIBS) # exercice 1 imageresize: imageresize.cxx Makefile $(CXX) $(FLAGS) $(INCLUDE) -o $@ $@.cxx $( LIBS) ...Frank Nielsen A1-90
  • 178. INF442 : Traitement des Données Massives A3 : Le clustering avec les k-moyennes et son extension en grandes dimensions avec Johnson-Lindenstrauss Frank Nielsen nielsen@lix.polytechnique.fr X2014 20 avril 2016 Frank Nielsen A1-1
  • 179. Règles pour le PA d’informatique Programme d’Approfondissement Informatique : https://programmes.polytechnique.fr/programme.php?id=999 ◮ avoir validé un projet en cours d’Info de 2A (modal compris) : indiquez cours et note a l’inscription ◮ au moins 2 cours d’info en 2A (hors modal) Responsable 3A : Sylvie Putot putot@lix.polytechnique.fr Frank Nielsen A1-2
  • 180. Le regroupement (clustering) = partitionner les données en groupes homogènes Frank Nielsen A1-3
  • 181. Le clustering plat = partitionner les données k = 3 clusters : Partition Chaque cluster a un représentant ⊗= prototype du cluster Frank Nielsen A1-4
  • 182. Exemple de clustering : observations du ciel Trouver les galaxies = amas d’objets célestes (=groupe, =cluster) Sloan Digital Sky Survey http://www.sdss.org/ plus de 3 millions d’objets célestes Frank Nielsen A1-5
  • 183. Dans les faits, on a une soupe d’attributs par donnée ... Jeu de n = 4898 données sur les vins, d = 11 attributs https://archive.ics.uci.edu/ml/datasets/Wine+Quality fixed acidity ;" volatile acidity ";" citric acid ";" residual sugar ";" chlorides ";" free sulfur dioxide ";" total sulfur dioxide ";" density ";" pH ";" sulphates ";" alcohol ";" quality" 7;0.27;0.36;20.7;0.045;45;170;1.001;3;0.45;8.8;6 6.3;0.3;0.34;1.6;0.049;14;132;0.994;3.3;0.49;9.5;6 ... 1 - fixed acidity 2 - volatile acidity 3 - citric acid 4 - residual sugar 5 - chlorides 6 - free sulfur dioxide 7 - total sulfur dioxide 8 - density 9 - pH 10 - sulphates 11 - alcohol On veut grouper les vins par “ressemblances” (par qualité, même qualité = même groupe). Attributs numériques ou catégoriques ⇒ définir la bonne notion de similarité/distance Frank Nielsen A1-6
  • 184. Recherche exploratoire : Le regroupement (clustering) Partitionner les données : ◮ X = {x1, ..., xn}, n données , chacune comportant d attributs : xi = (x (1) i , ..., x (j) i , ..., x (d) i ). Partitionne X en k ∈ N groupes disjoints = clusters : X = G1 ∪ G2 ∪ ... ∪ Gk, Gi ∩ Gj = ∅, ∀i = j ◮ permet de catégoriser les données en donnant un sens sémantique aux groupes homogènes → c’est l’apprentissage non-supervisé. ◮ Pour chaque groupe Gi , on peut définir un centre ci , appelé prototype ou représentant du cluster (sous-classe d’algorithmes appelé center-based clustering) ◮ ... mais le clustering/regroupement sert aussi à une quantité d’autres algorithmes ... Frank Nielsen A1-7
  • 185. Partitionner les données : le clustering Problème avec 3 types de grandeurs : ◮ n : le nombre de données ◮ d : la dimension des données X est visualisé comme un nuage de points dans Rd Attributs numériques, catégorielles ou semi-catégorielles ◮ k : le nombre de clusters (k ≤ n avec souvent k ≪ n) souvent inconnu a priori Généralement, on a n ≫ d (n très grand devant d) et k ≪ n (k très petit devant n, négligeable) inconnu, mais on peut aussi avoir d ≫ n et k = Θ(n) Notation : a ≫ b si a > b et a b = constante exp n ≫ n2 ≫ n ≫ log n n1+ǫ ≫ n loga n ∀ǫ > 0, a ∈ N Frank Nielsen A1-8
  • 186. Commençons avec le cas simple : k = 1 cluster Question = Comment trouver le centre ( = prototype) du cluster ? Un critère est de minimiser la variance du cluster = sa dispersion : v(X, c1) = n i=1 xi − c1 2 avec p − q 2 = d j=1(p(j) − q(j))2, la distance Euclidienne au carré p − q 2 = p − q, p − q où x, y = d j=1 x(j)y(j) = produit scalaire On veut minimiser : min c1 v(X, c1) = min c1 n i=1 xi − c1 2 Minimiser v(X, c1) ≡ minimiser 1 n v(G1, c1) (sa normalisation). Frank Nielsen A1-9
  • 187. Centre et variance d’un cluster ◮ Variance du cluster : minimise v1(X, c) min c v1(X, c) = n i=1 xi − c 2 ◮ Centre du cluster : c1 = arg min c v(X, c) = arg min c n i=1 xi − c 2 , v1(X) = v1(X, c1) arg min renvoie l’argument qui a donné lieu au minimum. En cas d’égalité, on renvoie le plus petit suivant un ordre donné. Par exemple, pour un tableau t[0] = −3, t[1] = 5, t[2] = −7, t[3] = 10, t[4] = −7, t[5] = 12. ordre ≤ sur les indexes entiers (ordre lexicographique) min i t[i] = −7, arg min i t[i] = 2 Frank Nielsen A1-10
  • 188. Rappel sur l’optimisation convexe ◮ Une fonction f ∈ C2 est strictement convexe ssi. pour x = y, ∀α ∈ (0, 1) f (αx+(1−α)y) < αf (x)+(1−α)f (y) ◮ équivalent à f ′′(x) > 0 (x ∈ R) ◮ minimum unique x∗ ssi ∃!x∗, f ′(x∗) = 0 (peut ne pas exister comme pour ex ) ◮ Analyse multivariée : vecteur Jacobien ∇x f (x) = (∂f (x) ∂xi )i et matrice Hessienne ∇2 x f (x) = (∂2f (x) ∂xi ∂xj )i,j ≻ 0 matrice positive définie x y (x, f(x)) (y, f(y)) αx + (1 − α)y f(αx + (1 − α)y) αf(x) + (1 − α)f(y) z = f(x) f(x) f(y) x∗ f(x∗ ) Frank Nielsen A1-11
  • 189. Centre de masse, centre de gravité ou centroïde Montrons que c1 = 1 n n i=1 xi = ¯x, est le centre de masse appelé aussi centroïde . min c1 n i=1 xi − c1, xi − c1 = n i=1 ( xi , xi − 2 xi , c1 + c1, c1 ) n i=1 xi , xi est une constante, et mettons donc à zéro les dérivées partielles de e(c1) = n i=1(−2 xi , c1 + c1, c1 ). ∇c1 e1(c1) = n i=1 (−2xi + 2c1) = 0 ⇒ c1 = 1 n n i=1 xi c1 est unique car les dérivées partielles secondes ∇2 c1 e1(c1) = diag(2, 2, ..., 2) sont strictement positives : e(c1) est donc strictement convexe. Frank Nielsen A1-12
  • 190. Illustration : petite et grande variances (dispersions) Petite et grande variance (dispersion) d’un cluster autour de son centre : v1(G1) = 1 n n i=1 xi − 1 n n l=1 xl 2 v1(G1) = 1 n n i=1 xi 2 − ¯x 2 , ¯x = 1 n n i=1 xi Frank Nielsen A1-13
  • 191. Le clustering par la fonction objective des k-moyennes On cherche à trouver les groupes avec les k centres c1, ..., ck (prototypes) qui minimise la fonction de coût ou fonction objective des k-moyennes : ek(X; c1, ..., ck) = ek(X; C) = n i=1 min j∈{1,...,k} xi − cj 2 C’est équivalent à ek(X; C) = k j=1 x∈Gj x − cj 2 avec Gj = {xi ∈ X : xi − cj ≤ xi − cl , ∀l ∈ {1, ..., k}} NB : En cas d’égalité des distances, on affecte suivant l’ordre lexicographique des clusters afin de respecter la propriété de partition . → On veut minimiser la somme pondérée des variances des clusters = somme des dispersions des clusters Frank Nielsen A1-14
  • 192. Tractabilité du clustering par les k-moyennes ◮ Calculer un clustering 1-moyenne coûte O(dn) (temps linéaire) ◮ Minimiser la fonction de coût des k-moyennes est NP-dur quand d > 1 et k > 1 ◮ Polynomial en temps O(n2k) quand d = 1 (1 attribut/donnée) par programmation dynamique → On va donc chercher des heuristiques pour résoudre les k-moyennes quand k > 1 et d > 1. Frank Nielsen A1-15
  • 193. Heuristiques pour les k-moyennes ◮ Heuristiques globales : on cherche les k centres des groupes sans configuration initiale des centres ◮ Heuristiques locales : on part d’une configuration des k centres, et on améliore localement avec des itérations la solution jusqu’à temps de converger vers un minimum local. Frank Nielsen A1-16
  • 194. Heuristique : initialisation aléatoire ◮ choisir les k graines distinctes (seeds) aléatoirement dans X. Méthode dite de Forgy centres initiaux = éléments de X ◮ choisir aléatoirement dans une boîte englobante qui contient les données ◮ Initialisation probabilies avec les k-moyennes++ ◮ etc. Frank Nielsen A1-17
  • 195. Heuristique de Lloyd : algorithme itératif “batch” À partir d’une configuration G1, ..., Gk (avec les centres c1, ..., ck), on améliore itérativement la solution avec ces deux étapes : Allocation des données aux groupes. Pour tout xi ∈ X, soit li = arg minl xi − cl 2, et formons les groupes Gj = {xi : li = j} de cardinalité nj = |Gj |. (ici, distance ou distance au carré donne la même allocation) Mise à jour des centres des groupes. Pour tout j ∈ [k] = {1, ..., k}, calculer le centre de masse : cj = 1 nj x∈Gj x. On a donc minimisé pour chaque cluster 1 nj x∈Gj x − cj 2. Si on remplace distance au carré par distance, on obtient le point de Fermat-Weber qui n’admet pas de formule close. Répeter ces deux étapes jusqu’à convergence ou amélioration de la fonction objective qui passe sous un seuil. Frank Nielsen A1-18
  • 196. Allocation des données aux groupes : partition de Voronoï c1 c2 c3c4 c5 c6 p|lC(p) = 1 q|lC(q) = 3 Vj = {x ∈ Rd : x − cj ≤ x − cl , ∀l ∈ {1, ..., n}}. lC (x) = arg k min j=1 x − cj 2 Frank Nielsen A1-19
  • 197. Convergence de l’algorithme itératif de Lloyd Théorème Les k-moyennes de Lloyd converge de façon monotone en un nombre fini d’étapes. Soit G(Ct) = {G (t) 1 , ..., G (t) k } la partition de X à l’étape t de coût ck(X, Ct). A l’étape t + 1, puisqu’on alloue les points aux clusters dont les centres sont les plus proches, on minimise donc : ck(G(C(t+1) ), Ct) ≤ ck(X, Ct) Rappelons que l’on a ck(G(C(l)), Cl ) = k j=1 v(G (l) j , cj ) (somme des variances des clusters). Lors de la remise à jour des centres par les centroïdes des groupes, pour chaque groupe on a v(G (t+1) j , c(t+1) = c(G (t+1) j )) ≤ v(G (t+1) j , c (t) j ), et donc : ck(X, Ct+1) ≤ ck(G(C(t+1) ), Ct) ≤ ck(X, Ct) Frank Nielsen A1-20
  • 198. L’heuristique de Lloyd en action : les points initiaux n = 16 points (•) et k = 2 graines (×) Frank Nielsen A1-21
  • 199. L’heuristique de Lloyd en action affectation des points aux centres (étape 1) Frank Nielsen A1-22
  • 200. L’heuristique de Lloyd en action nouveaux centres = centroïdes des groupes (étape 1) Frank Nielsen A1-23
  • 201. L’heuristique de Lloyd en action affectation des points aux centres (étape 2) Frank Nielsen A1-24
  • 202. L’heuristique de Lloyd en action nouveaux centres = centroïdes des groupes (étape 2) Frank Nielsen A1-25
  • 203. L’heuristique de Lloyd en action convergence : lorsque les points sont alloués aux mêmes groupes (étape 3) que lors de la précédente itération étape 2 étape 3 Frank Nielsen A1-26
  • 204. Démo Les k-moyennes de Lloyd Frank Nielsen A1-27
  • 205. Algorithme de Lloyd : le cas des clusters vides On peut avoir des clusters qui deviennent vides (cas “rares” en pratique mais qui augmente avec la dimension !). Dans ce cas, on peut partiellement rechoisir une ou des nouvelles graines, et la somme des variances des clusters continue à diminuer (partial reseeding) Frank Nielsen A1-28
  • 206. Un nombre potentiel exponentiel de minima locaux ! La fonction de coût des k-moyennes peut avoir un nombre exponentiel de minima locaux. ◮ minimum global 0.375 : (a) et (b) ◮ minima locaux ∼ 0.5417 : (c) et (d) On réplique ce sous-ensemble en paquets en les éloignant très loins les uns des autres Frank Nielsen A1-29
  • 207. Algorithme de Lloyd (1957) ◮ En théorie, l’heuristique de Lloyd peut boucler un nombre exponentiellement de fois (linéaire en 1D). ... et souvenons nous que minimiser les k-moyennes sont NP-durs ◮ Marche expérimentalement très bien : implémenter un critère pour stopper les itérations lorsque la décroissance de la fonction de coût passe sous un seuil donné : Par exemple, ek(X, Ct) − ek(X, Ct+1) ≤ ǫ (ou seuil relatif en pourcentage). ◮ Complexité de Lloyd : O(dn) en mémoire et O(dns) où s = nombre d’itérations. ◮ ⇒ de nombreuses variantes et analyses de complexité ! Frank Nielsen A1-30
  • 208. k-moyennes : le choix du nombre de clusters k ◮ Un problème important : déterminer le nombre de clusters k ◮ Pour n’importe quel k, on a la fonction k-moyenne optimale ek(X) (évaluer empiriquement avec l’heuristique de Lloyd sur plusieurs initialisations) ◮ ek(X) décroit de façon monotone jusqu’à en(X) = 0 Cas limite : un point par cluster ⇒ variance nulle Méthode du coude : on dessine la fonction (k, ek(X)) et on choisit k au niveau du coude (elbow). k 2 3 4 5 6 7 8 9 10 fonctiondecoˆutdesk-moyennesek(X) avant-brasbras coude Frank Nielsen A1-31
  • 209. Les limitations de la technique des k-moyennes Permet de trouver des clusters dont les enveloppes convexes des groupes sont deux à deux séparables (propriété des diagrammes de Voronoï). Par exemple, ne permet pas de partitionner correctement ce jeu de données : Pour information, ce problème est résolu par les k-moyennes à noyau Frank Nielsen A1-32
  • 210. Vérité terrain (groundtruth) ◮ Sans vérité terrain, une analyse subjective des clusters permet de mettre en valeur telle ou telle technique de clustering. Mais quand d > 3 comment visualiser ? → Réduction de dimension linéaire (ACP) ou apprentissage de variétés (manifold learning) ◮ Lorsque l’on dispose de vérités terrains par des jeux de données dont on connaît déjà l’appartenance aux clusters (c’est-à-dire la classe pour chaque donnée), on peut calculer divers indexes qui montrent la concordance du résultat avec celui étiqueté (supposé optimal). ◮ Notez le problème ambigü de l’étiquettage puisque les clusters ne sont pas forcément numérotés avec les mêmes numéros : on doit faire face potentiellement à k! permutations. Frank Nielsen A1-33
  • 211. L’indexe de Rand : similarité entre deux clusterings indexe de Rand = Mesure de similarité entre deux clusterings G = ⊎Gi et G′ = ⊎G′ i (disons, celui obtenu par les k-moyennes et un jeu de données correctement étiqueté). Compare toutes les n 2 paires (xi , xj ) de points et compte ceux qui se trouvent dans les mêmes clusters (a) et ceux qui se trouvent dans des clusters différents (b). R(G, G′ ) = a + b n 2 , 0 ≤ R ≤ 1 ◮ a : #{(i, j) : l(xi ) = l(xj ) ∧ l′(xi ) = l′(xj )} ◮ b : #{(i, j) : l(xi ) = l(xj ) ∧ l′(xi ) = l′(xj )} Condition1 ∧ Condition2 : vrai ssi. Condition 1 et 2 sont vraies On a évité ainsi de renuméroter les k groupes (k! permutations). Frank Nielsen A1-34
  • 213. Parallélisation : propriété de (dé)composition du centroïde X et X′ : deux jeux de données pondérées ¯x(X) : barycentre de X, ¯x(X) = 1 w(X) x∈X w(x)x W = w(X) = x∈X w(x) et W ′ = w(X′). Décomposabilité du barycentre : ¯x(X ∪ X′ ) = W W + W ′ ¯x(X) + W ′ W + W ′ ¯x(X′ ) ◮ très utile pour partager le calcul des données sur plusieurs processeurs ... ◮ propriété de la géométrie Euclidienne (par exemple, n’est pas vrai en géométrie hyperbolique) Frank Nielsen A1-36
  • 214. Parallélisation de l’heuristique de Lloyd Soit p processus/processeurs P0, ..., Pp−1 Chaque machine/processus a sa propre mémoire vive n données, d dimensions/donnée (= attributs) ◮ au départ, tous les processus lisent leurs données, ou alors le processus racine partitionne et envoie les données à tous les autres processus = diffusion, une opération de communication globale ◮ Le processus racine choisit les k graînes (= prototypes initiaux), et les diffuse à tous les autres processus ◮ chaque processus Pr s’occupe d’ un paquet de n p données Xr = {xr n p ...x(r+1) n p −1} en calculant la distance minimale de ses xi aux centres. On met à jour la fonction de coût, et on calcule les centroïdes et cardinalité indépendamment dans chaque paquet : G1(r), ..., Gk(r) avec n1(r) = |G1(r)|, ..., nk(r) = |Gk(r)|. Frank Nielsen A1-37
  • 215. Parallélisation de l’heuristique de Lloyd ◮ puis on agrége tous les cj (r) et nj (r) (opération reduce) en faisant des opérations de sommes cumulées (= calcul collaboratif) ◮ et on répète jusqu’à convergence, ou lorsque la décroissance de la fonction de coût passe sous un seuil. Frank Nielsen A1-38
  • 217. Les k-moyennes en parallèle : analyse de la complexité ◮ Les opérations élémentaires de communications globales comme la diffusion (Bcast) et de calculs globaux comme l’agrégation (Reduce) dépendent de comment les machines sont reliées entre elles = topologie du réseau d’interconnexion du cluster de machines . ◮ Initialisation des centres initiaux par le processeur racine P0 en temps O(dk) ◮ Coût total de la parallélisation : O dk + Bcast(p, dk) + s dn p + Reduce(p, dk) ∼n≫k,d O dkns p ◮ → Facteur d’accélération (speed-up, rapport du temps séquentiel sur le temps parallèle) α = O dkns dkns p = O(p). Frank Nielsen A1-40
  • 218. Réduction de dimension linéaire avec le théorème de Johnson-Lindenstrauss Frank Nielsen A1-41
  • 219. Le fléau des grandes dimensions ! Curse of dimensionality Bellman, inventeur de la programmation dynamique ◮ efficacité des algorithmes dépend de la dimension d des attributs : ◮ calcul de distances ou de similarités en Ω(d) ◮ algorithmes et structures de données souvent avec une constante exponentielle en d cachée dans la notation O(·) : Od (1). ◮ difficile de visualiser les données en grandes dimensions ◮ dimension ambiante (= extrinséque) versus dimension intrinsèque Aujourd’hui, dans le traitement des données : ◮ très courant de travailler en dimension 1000 et bien plus ! ◮ cas aussi où d ≫ n (dimension extrinséque ≫ dimension intrinséque) Frank Nielsen A1-42
  • 220. Des phénoménes non-intuitifs en grandes dimensions ! ◮ volume de la balle inscrite dans le cube unité tend vers zéro : Bd = π d 2 Γ(d 2 + 1) rd , r = 1 2 , Γ(t) = ∞ 0 xt−1 e−x dx ◮ grille régulière de Rd en l sous-divisions par côté partitionne l’espace en ld hypercubes : exponentiel en d (ld = ed log l ). L’approche de la grille adaptative ne permet pas non plus de passer à l’échelle ... ◮ intégration stochastique à la Monte-Carlo ( ≈ ) devient inutilisable ... ◮ on ne distingue plus le plus proche voisin du plus lointain voisin ... “... the distance to the nearest data point approaches the distance to the farthest data point ...” (Beyer, 1999) Frank Nielsen A1-43
  • 221. Exemple 1 : trouver les images dupliquées Problème : near duplicate image detection ◮ une image I[y][x] en couleur RVB de taille w × h est convertie en un vecteur v(I) de dimension R3wh (vectorization) ◮ la distance entre deux images I1 et I2 est la somme des différences au carré ( sum of squared differences ) : SSD(I1, I2) = h i=1 w j=1 (I1[i][j] − I2[i][j])2 = v(I1) − v(I2) 2 ◮ une image est en double dans une base d’images si son Plus Proche Voisin (PPV) est quasiment identique : SSD(I, PPV(I)) ≤ ǫ ⇒ comment calculer les plus proches voisins en grandes dimensions en temps sous-linéaire, o(d) ? Frank Nielsen A1-44
  • 222. Exemple 2 : regrouper une collection d’images Exemple de la base MNIST des chiffres postaux (US) : n = 60000, d = 282 = 784 Idéalement, trouver les dix clusters pour les chiffres de ’0’ à ’9’ ◮ utiliser l’algorithme des k-moyennes de Lloyd en dimension 784 est trop lent ... ◮ comment faire ? → réduire la dimension en conservant la notion de distance http://yann.lecun.com/exdb/mnist/ Frank Nielsen A1-45
  • 223. La réduction de dimension : formuler le problème ◮ données X : n points de Rd ◮ X interprété comme une matrice de taille n × d une donnée par ligne, vecteur ligne = matrice fine (thin vs fat matrix) ◮ Deux techniques pour réduire la dimension : ◮ sélectionner les dimensions à conserver (feature selection) ◮ recomposer les dimensions existantes en de nouvelles dimensions tout en gardant l’“information” (la notion de distance) Frank Nielsen A1-46
  • 224. La réduction de dimension linéaire Associons un vecteur y = y(x) ∈ Rk à tout x ∈ Rd : A : Rd → Rk Lorsque y(x) est une fonction linéaire, écriture matricielle : y (1,k) = x (1,d) × A (d,k) , Y = X × A A matrice de taille d × k (x et y = vecteurs lignes) ⇒ Y doit être “fidèle” à X : ∀x, x′ ∈ X, y − y′ 2 = xA − x′ A 2 ≈ x − x 2 X × A : représentation compacte de X, taille kn au lieu de dn Frank Nielsen A1-47
  • 225. Le théorème de Johnson-Lindenstrauss (1984) Soit X n points de Rd et ǫ ∈ (0, 1), alors il existe une transformation linéaire A : Rd → Rk avec k = O( 1 ǫ2 log n) telle que : ∀x, x′ ∈ X, (1 − ǫ) x − x′ 2 ≤ xA − x′ A 2 ≤ (1 + ǫ) x − x′ 2 →low distortion embedding (différent du cas où c’est parfait = plongement iso-métrique) On passe de la dimension d à la dimension k = O( 1 ǫ2 log n) C’est indépendant de la dimension ambiante d ! ! ! Frank Nielsen A1-48
  • 226. Matrices A pour les projection aléatoires Projection aléatoire A : ◮ On tire les coefficients de la matrice A′ aléatoirement suivant une loi normale/Gaussienne standard (iid) : A′ = [ai,j ], ai,j ∼ N(0, 1) ◮ On obtient un échantillon aléatoire d’une loi normale standard N(0, 1) à partir de lois uniformes U1 et U2 indépendantes par : N = −2 log U1 cos(2πU2) ← transformation de Box-Müller ◮ on ajuste l’échelle : A = k d A′ Frank Nielsen A1-49
  • 227. Pourquoi ça marche : les projections aléatoires ◮ soit un espace k-affine aléatoire A avec k ≥ 4 log n ǫ2 2 − ǫ3 3 . ◮ notons ˜x = d k projAx = projection orthogonale de x sur A. Lemme : ∀p, q ∈ X, P ˜p − ˜q 2 p − q 2 ∈ [1 − ǫ, 1 + ǫ] ≤ 2 n2 ◮ Preuve : Probabilité que ˜x satisfasse le théorème JL : ≥ 1 − n 2 2 n2 = 1 n ◮ On peut choisir O(n) projections et garantir une probabilité de succès constante Frank Nielsen A1-50
  • 228. Résultats récents sur les transformations de Johnson-Lindenstrauss ◮ k = Ω(ǫ−2 log n), optimal pour les transformations linéaires The Johnson-Lindenstrauss lemma is optimal for linear dimensionality reduction, 2014 ◮ matrice avec poids dans Z (Achlioptas, 2003) : ai,j =    1 avec probabilité 1 6 0 avec probabilité 2 3 −1 avec probabilité 1 6 ◮ matrices creuses : O(1 ǫ ) coefficients non-nuls/ligne Sparser Johnson-Lindenstrauss transforms, J. ACM, 2014 Frank Nielsen A1-51
  • 229. Le TD d’aujourd’hui ... Regrouper des images ! Implémenter les “Johnson-Lindenstrauss k-moyennes” pour une base d’images ! On va passer de R300×300×3 = R270000 à R532 tout en trouvant des partitions semblables ... Grand gain de rapidité ! Complexité passant de O(sdkn) à Oǫ(skn log n) où s est le nombre d’itérations (avec Oǫ(nd log n) pour calculer les projections) Utiliser une bibliothèque externe CImg, rentrer dans du code C++ STL Frank Nielsen A1-52
  • 230. Le TD d’aujourd’hui ... Regrouper des images ! Quelques images retournées par une requête ’spaghetti’ d’un moteur de recherche : Frank Nielsen A1-53
  • 231. Le TD d’aujourd’hui ... Regrouper des images ! Ces images regroupées en thème ( = clusters) : Frank Nielsen A1-54