Advertisement
milanmetal

kmeans omp iskomentarisan

Dec 5th, 2018
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.47 KB | None | 0 0
  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2. /*   File:         kmeans_clustering.c  (OpenMP version)                     */
  3. /*   Description:  Implementation of simple k-means clustering algorithm     */
  4. /*                 This program takes an array of N data objects, each with  */
  5. /*                 M coordinates and performs a k-means clustering given a   */
  6. /*                 user-provided value of the number of clusters (K). The    */
  7. /*                 clustering results are saved in 2 arrays:                 */
  8. /*                 1. a returned array of size [K][N] indicating the center  */
  9. /*                    coordinates of K clusters                              */
  10. /*                 2. membership[N] stores the cluster center ids, each      */
  11. /*                    corresponding to the cluster a data object is assigned */
  12. /*                                                                           */
  13. /*   Author:  Wei-keng Liao                                                  */
  14. /*            ECE Department, Northwestern University                        */
  15. /*            email: [email protected]                             */
  16. /*                                                                           */
  17. /*   Copyright (C) 2005, Northwestern University                             */
  18. /*   See COPYRIGHT notice in top-level directory.                            */
  19. /*                                                                           */
  20. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24.  
  25. #include <omp.h>
  26. #include "kmeans.h"
  27.  
  28.  
  29. /*----< euclid_dist_2() >----------------------------------------------------*/
  30. /* square of Euclid distance between two multi-dimensional points            */
  31. __inline static
  32. float euclid_dist_2(int    numdims,  /* no. dimensions */
  33.                     float *coord1,   /* [numdims] */
  34.                     float *coord2)   /* [numdims] */
  35. {
  36.     int i;
  37.     float ans=0.0;
  38.  
  39.     for (i=0; i<numdims; i++)
  40.         ans += (coord1[i]-coord2[i]) * (coord1[i]-coord2[i]);
  41.  
  42.     return(ans);
  43. }
  44.  
  45. /*----< find_nearest_cluster() >---------------------------------------------*/
  46. __inline static
  47. int find_nearest_cluster(int     numClusters, /* no. clusters */
  48.                          int     numCoords,   /* no. coordinates */
  49.                          float  *object,      /* [numCoords] */
  50.                          float **clusters)    /* [numClusters][numCoords] */
  51. {
  52.     int   index, i;
  53.     float dist, min_dist;
  54.  
  55.     /* find the cluster id that has min distance to object */
  56.     index    = 0;
  57.     min_dist = euclid_dist_2(numCoords, object, clusters[0]);
  58.  
  59.     for (i=1; i<numClusters; i++) {
  60.         dist = euclid_dist_2(numCoords, object, clusters[i]);
  61.         /* no need square root */
  62.         if (dist < min_dist) { /* find the min and its array index */
  63.             min_dist = dist;
  64.             index    = i;
  65.         }
  66.     }
  67.     return(index);
  68. }
  69.  
  70.  
  71. /*----< kmeans_clustering() >------------------------------------------------*/
  72. /* return an array of cluster centers of size [numClusters][numCoords]       */
  73. int omp_kmeans(int     is_perform_atomic, /* in: */
  74.                float **objects,           /* in: [numObjs][numCoords] */
  75.                int     numCoords,         /* no. coordinates */
  76.                int     numObjs,           /* no. objects */
  77.                int     numClusters,       /* no. clusters */
  78.                float   threshold,         /* % objects change membership */
  79.                int    *membership,        /* out: [numObjs] */
  80.                float **clusters)          /* out: [numClusters][numCoords] */
  81. {
  82.     int      i, j, k, index, loop=0;
  83.     int     *newClusterSize; /* [numClusters]: no. objects assigned in each
  84.                                 new cluster */
  85.     float    delta;          /* % of objects change their clusters */
  86.     float  **newClusters;    /* [numClusters][numCoords] */
  87.     double   timing;
  88.  
  89.     int      nthreads;             /* no. threads */
  90.     int    **local_newClusterSize; /* [nthreads][numClusters] */
  91.     float ***local_newClusters;    /* [nthreads][numClusters][numCoords] */
  92.  
  93.     nthreads = omp_get_max_threads();
  94.  
  95.     /* initialize membership[] */
  96.     for (i=0; i<numObjs; i++) membership[i] = -1;
  97.  
  98.     /* need to initialize newClusterSize and newClusters[0] to all 0 */
  99.     newClusterSize = (int*) calloc(numClusters, sizeof(int));
  100.     assert(newClusterSize != NULL);
  101.  
  102.     /* NOTE: float**, niz pokazivaca na float, numClusters komada nizova
  103.     /* koji cuvaju pokazivace na float... */
  104.     /* newClusters zapravo predstavljaju predstavnike klastera, */
  105.     /* svaki klaster ima niz sa numCoords podataka koji predstavljaju */
  106.     /* koordinate centralne tacke klastera. */
  107.     newClusters    = (float**) malloc(numClusters *            sizeof(float*));
  108.     assert(newClusters != NULL);
  109.  
  110.     /* Slican problem, podsetnik */
  111.     /* --------------------------------- */
  112.     /* Primer 4: */
  113.     /* https://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/ */
  114.           /* int r=3, c=4, len=0; */
  115.           /* int *ptr, **arr; */
  116.           /* int count = 0,i,j; */
  117.  
  118.           /* len = sizeof(int *) * r + sizeof(int) * c * r; */
  119.           /* arr = (int **)malloc(len); */
  120.  
  121.           /* // ptr is now pointing to the first element in of 2D array */
  122.           /* ptr = arr + r; */
  123.  
  124.     /* --> +r u poslednjoj liniji, imam r redova, koji predstavljaju pokazivace */
  125.     /*       na sadrzaje tih redova, zato preskacem pokazivace i dolazim do */
  126.     /*       prvog elementa... dakle, u istom alociranom prostoru sam uzeo */
  127.     /*       memoriju i za pokazivace i za sadrzaj elemenata matrice. */
  128.  
  129.     /* NOTE: sada uzimam jedan od tih numClusters komada i dodjeljujem mu */
  130.     /* memoriju za numClusters*numCoords podataka float */
  131.     newClusters[0] = (float*)  calloc(numClusters * numCoords, sizeof(float));
  132.  
  133.     /* NOTE: calloc i malloc zauzimaju blok memorije i vracaju pointer na */
  134.     /*      alocirani blok, NA POCETAK BLOKA! */
  135.  
  136.     /* NOTE: potvrdjujem da je ta memorija zaista dodeljena */
  137.     assert(newClusters[0] != NULL);
  138.  
  139.     /* NOTE: u ovom trenutku imam alociran blok memorije velicine */
  140.     /*   numClusters*numCoords... newClusters[0] drzi pokazivac na pocetak tog */
  141.     /*   bloka, zato krecem od njega, ova petlja ispod generise sve ostale tako */
  142.     /*   sto newClusters[1] dobijam kada newClusters[0] ptr uvecam za numCoords */
  143.     /*   znaci uzimam pocetak bloka i pomjeram se za numCoords mjesta u */
  144.     /*   adresnom prostoru, to znaci da si ostavio numCoords pozicija za */
  145.     /*   newClusters[0], a to ima smisla --> numCoords polja za koordinate */
  146.     /*   nultog klastera. */
  147.     for (i=1; i<numClusters; i++)
  148.         newClusters[i] = newClusters[i-1] + numCoords;
  149.  
  150.     /* NOTE: U ovom trenutku imam sve klastere inicijalizovane, dodeljena im je */
  151.     /*      memorija za sve koordinate koje treba sacuvaju. */
  152.  
  153.     if (!is_perform_atomic) {
  154.         /* each thread calculates new centers using a private space,
  155.            then thread 0 does an array reduction on them. This approach
  156.            should be faster */
  157.         local_newClusterSize    = (int**) malloc(nthreads * sizeof(int*));
  158.         assert(local_newClusterSize != NULL);
  159.         local_newClusterSize[0] = (int*)  calloc(nthreads*numClusters,
  160.                                                  sizeof(int));
  161.         assert(local_newClusterSize[0] != NULL);
  162.         for (i=1; i<nthreads; i++)
  163.             local_newClusterSize[i] = local_newClusterSize[i-1]+numClusters;
  164.  
  165.         /* local_newClusters is a 3D array */
  166.         local_newClusters    =(float***)malloc(nthreads * sizeof(float**));
  167.         assert(local_newClusters != NULL);
  168.         local_newClusters[0] =(float**) malloc(nthreads * numClusters *
  169.                                                sizeof(float*));
  170.         assert(local_newClusters[0] != NULL);
  171.         for (i=1; i<nthreads; i++)
  172.             local_newClusters[i] = local_newClusters[i-1] + numClusters;
  173.         for (i=0; i<nthreads; i++) {
  174.             for (j=0; j<numClusters; j++) {
  175.                 local_newClusters[i][j] = (float*)calloc(numCoords,
  176.                                                          sizeof(float));
  177.                 assert(local_newClusters[i][j] != NULL);
  178.             }
  179.         }
  180.     }
  181.  
  182.     if (_debug) timing = omp_get_wtime();
  183.     do {
  184.         delta = 0.0;
  185.  
  186.         if (is_perform_atomic) {
  187.             #pragma omp parallel for \
  188.                     private(i,j,index) \
  189.                     firstprivate(numObjs,numClusters,numCoords) \
  190.                     shared(objects,clusters,membership,newClusters,newClusterSize) \
  191.                     schedule(static) \
  192.                     reduction(+:delta)
  193.             for (i=0; i<numObjs; i++) {
  194.                 /* find the array index of nestest cluster center */
  195.                 index = find_nearest_cluster(numClusters, numCoords, objects[i],
  196.                                              clusters);
  197.  
  198.                 /* if membership changes, increase delta by 1 */
  199.                 if (membership[i] != index) delta += 1.0;
  200.  
  201.                 /* assign the membership to object i */
  202.                 membership[i] = index;
  203.  
  204.                 /* update new cluster centers : sum of objects located within */
  205.                 #pragma omp atomic
  206.                 newClusterSize[index]++;
  207.                 for (j=0; j<numCoords; j++)
  208.                     #pragma omp atomic
  209.                     newClusters[index][j] += objects[i][j];
  210.             }
  211.         }
  212.         else {
  213.             #pragma omp parallel \
  214.                     shared(objects,clusters,membership,local_newClusters,local_newClusterSize)
  215.             {
  216.                 int tid = omp_get_thread_num();
  217.                 #pragma omp for \
  218.                             private(i,j,index) \
  219.                             firstprivate(numObjs,numClusters,numCoords) \
  220.                             schedule(static) \
  221.                             reduction(+:delta)
  222.                 for (i=0; i<numObjs; i++) {
  223.                     /* find the array index of nestest cluster center */
  224.                     index = find_nearest_cluster(numClusters, numCoords,
  225.                                                  objects[i], clusters);
  226.  
  227.                     /* if membership changes, increase delta by 1 */
  228.                     if (membership[i] != index) delta += 1.0;
  229.  
  230.                     /* assign the membership to object i */
  231.                     membership[i] = index;
  232.  
  233.                     /* update new cluster centers : sum of all objects located
  234.                        within (average will be performed later) */
  235.                     local_newClusterSize[tid][index]++;
  236.                     for (j=0; j<numCoords; j++)
  237.                         local_newClusters[tid][index][j] += objects[i][j];
  238.                 }
  239.             } /* end of #pragma omp parallel */
  240.  
  241.             /* let the main thread perform the array reduction */
  242.             for (i=0; i<numClusters; i++) {
  243.                 for (j=0; j<nthreads; j++) {
  244.                     newClusterSize[i] += local_newClusterSize[j][i];
  245.                     local_newClusterSize[j][i] = 0.0;
  246.                     for (k=0; k<numCoords; k++) {
  247.                         newClusters[i][k] += local_newClusters[j][i][k];
  248.                         local_newClusters[j][i][k] = 0.0;
  249.                     }
  250.                 }
  251.             }
  252.         }
  253.  
  254.         /* average the sum and replace old cluster centers with newClusters */
  255.         for (i=0; i<numClusters; i++) {
  256.             for (j=0; j<numCoords; j++) {
  257.                 if (newClusterSize[i] > 1)
  258.                     clusters[i][j] = newClusters[i][j] / newClusterSize[i];
  259.                 newClusters[i][j] = 0.0;   /* set back to 0 */
  260.             }
  261.             newClusterSize[i] = 0;   /* set back to 0 */
  262.         }
  263.  
  264.         delta /= numObjs;
  265.     } while (delta > threshold && loop++ < 500);
  266.  
  267.     if (_debug) {
  268.         timing = omp_get_wtime() - timing;
  269.         printf("nloops = %2d (T = %7.4f)",loop,timing);
  270.     }
  271.  
  272.     if (!is_perform_atomic) {
  273.         free(local_newClusterSize[0]);
  274.         free(local_newClusterSize);
  275.  
  276.         for (i=0; i<nthreads; i++)
  277.             for (j=0; j<numClusters; j++)
  278.                 free(local_newClusters[i][j]);
  279.         free(local_newClusters[0]);
  280.         free(local_newClusters);
  281.     }
  282.     free(newClusters[0]);
  283.     free(newClusters);
  284.     free(newClusterSize);
  285.  
  286.     return 1;
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement