private static void test01() //****************************************************************************80 // // Purpose: // // TEST01 tests ADJ_SET. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 04 January 2007 // // Author: // // John Burkardt // { const int NODE_NUM = 10; const int ADJ_MAX = NODE_NUM * (NODE_NUM - 1); int[] adj = new int[ADJ_MAX]; int adj_num = 0; int[] adj_row = new int[NODE_NUM + 1]; int k; int seed = 123456789; Console.WriteLine(""); Console.WriteLine("TEST01"); Console.WriteLine(" ADJ_SET sets up an adjacency matrix incrementally."); int n_calls = UniformRNG.i4_uniform(1, ADJ_MAX, ref seed); AdjacencyMatrix.adj_set(NODE_NUM, ADJ_MAX, ref adj_num, ref adj_row, ref adj, -1, -1); Console.WriteLine(""); Console.WriteLine(" Creating and recording adjacency information:"); Console.WriteLine(""); for (k = 1; k <= n_calls; k++) { int i = UniformRNG.i4_uniform(1, NODE_NUM, ref seed); int j = UniformRNG.i4_uniform(1, NODE_NUM, ref seed); Console.WriteLine(" " + i.ToString().PadLeft(8) + " " + j.ToString().PadLeft(8) + ""); AdjacencyMatrix.adj_set(NODE_NUM, ADJ_MAX, ref adj_num, ref adj_row, ref adj, i, j); } AdjacencyMatrix.adj_print(NODE_NUM, adj_num, adj_row, adj, " Random adjacency matrix:"); AdjacencyMatrix.adj_show(NODE_NUM, adj_num, adj_row, adj); }
public static int[] perm_uniform(int n, int base_, ref int seed) //****************************************************************************80 // // Purpose: // // PERM_UNIFORM selects a random permutation of N objects. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 31 October 2008 // // Author: // // John Burkardt // // Reference: // // Albert Nijenhuis, Herbert Wilf, // Combinatorial Algorithms, // Academic Press, 1978, second edition, // ISBN 0-12-519260-6. // // Parameters: // // Input, int N, the number of objects to be permuted. // // Input, int BASE, is 0 for a 0-based permutation and 1 for // a 1-based permutation. // // Input/output, int *SEED, a seed for the random number generator. // // Output, int PERM_UNIFORM[N], a permutation of (BASE, BASE+1, ..., BASE+N-1). // { int[] p = new int[n]; for (int i = 0; i < n; i++) { p[i] = i + base_; } for (int i = 0; i < n; i++) { int j = UniformRNG.i4_uniform(i, n - 1, ref seed); (p[i], p[j]) = (p[j], p[i]); } return(p); }
private static void test055( ) //****************************************************************************80 // // Purpose: // // TEST055 tests OR on long long ints. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 12 May 2007 // // Author: // // John Burkardt // { int seed = 123456789; Console.WriteLine(); Console.WriteLine("TEST055"); Console.WriteLine(" The function ^ computes the bitwise exclusive OR"); Console.WriteLine(" of two LONG LONG INT's."); Console.WriteLine(); Console.WriteLine(" I J I^J"); Console.WriteLine(); for (int test = 1; test <= 10; test++) { long i = UniformRNG.i4_uniform(0, 100, ref seed); long j = UniformRNG.i4_uniform(0, 100, ref seed); long k = i ^ j; string cout = " "; string t = i.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; t = j.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; t = k.ToString(CultureInfo.InvariantCulture).PadLeft(6); cout += t; Console.WriteLine(cout); } }
private static void or_test( ) //****************************************************************************80 // // Purpose: // // OR_TEST tests OR. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 January 2007 // // Author: // // John Burkardt // { int seed = 123456789; Console.WriteLine(); Console.WriteLine("OR_TEST"); Console.WriteLine(" The function ^ computes the bitwise exclusive OR"); Console.WriteLine(" of two integers."); Console.WriteLine(); Console.WriteLine(" I J I^J"); Console.WriteLine(); for (int test = 1; test <= 10; test++) { int i = UniformRNG.i4_uniform(0, 100, ref seed); int j = UniformRNG.i4_uniform(0, 100, ref seed); int k = i ^ j; string cout = " "; string t = i.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; t = j.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; t = k.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; Console.WriteLine(cout); } }
private static void i4_bit_hi1_test( ) //****************************************************************************80 // // Purpose: // // I4_BIT_HI1_TEST tests I4_BIT_HI1. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 January 2007 // // Author: // // John Burkardt // { int seed = 123456789; Console.WriteLine(); Console.WriteLine("I4_BIT_HI1_TEST"); Console.WriteLine(" I4_BIT_HI1 returns the location of the high bit in an integer."); Console.WriteLine(); Console.WriteLine(" I I4_BIT_HI1(I)"); Console.WriteLine(); for (int test = 1; test <= 10; test++) { int i = UniformRNG.i4_uniform(0, 100, ref seed); int j = SobolSampler.i4_bit_hi1(i); string cout = " "; string t = i.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; cout += t; t = j.ToString(CultureInfo.InvariantCulture).PadLeft(6); cout += t; Console.WriteLine(cout); } }
private static void i8_bit_lo0_test( ) //****************************************************************************80 // // Purpose: // // I8_BIT_LO0_TEST tests I8_BIT_LO0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 12 May 2007 // // Author: // // John Burkardt // { int seed = 123456789; Console.WriteLine(); Console.WriteLine("I8_BIT_LO0_TEST"); Console.WriteLine(" I8_BIT_LO0 returns the location of the low zero bit"); Console.WriteLine(" in an integer."); Console.WriteLine(); Console.WriteLine(" I I8_BIT_LO0(I)"); Console.WriteLine(); for (int test = 1; test <= 10; test++) { long i = UniformRNG.i4_uniform(0, 100, ref seed); int j = SobolSampler.i8_bit_lo0(i); string cout = " "; string t = i.ToString(CultureInfo.InvariantCulture).PadLeft(6) + " "; t += j.ToString(CultureInfo.InvariantCulture).PadLeft(6); cout += t; Console.WriteLine(cout); } }
public static void triangulation_search_delaunay(int node_num, double[] node_xy, int triangle_order, int triangle_num, int[] triangle_node, int[] triangle_neighbor, double[] p, ref int triangle, ref int edge, int pIndex = 0) //****************************************************************************80 // // Purpose: // // TRIANGULATION_SEARCH_DELAUNAY searches a triangulation for a point. // // Discussion: // // The algorithm "walks" from one triangle to its neighboring triangle, // and so on, until a triangle is found containing point P, or P is found // to be outside the convex hull. // // The algorithm computes the barycentric coordinates of the point with // respect to the current triangle. If all three quantities are positive, // the point is contained in the triangle. If the I-th coordinate is // negative, then (X,Y) lies on the far side of edge I, which is opposite // from vertex I. This gives a hint as to where to search next. // // For a Delaunay triangulation, the search is guaranteed to terminate. // For other triangulations, a cycle may occur. // // Note the surprising fact that, even for a Delaunay triangulation of // a set of nodes, the nearest point to (X,Y) need not be one of the // vertices of the triangle containing (X,Y). // // The code can be called for triangulations of any order, but only // the first three nodes in each triangle are considered. Thus, if // higher order triangles are used, and the extra nodes are intended // to give the triangle a polygonal shape, these will have no effect, // and the results obtained here might be misleading. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 27 September 2006 // // Author: // // Barry Joe, // Department of Computing Science, // University of Alberta, // Edmonton, Alberta, Canada T6G 2H1 // // Reference: // // Barry Joe, // GEOMPACK - a software package for the generation of meshes // using geometric algorithms, // Advances in Engineering Software, // Volume 13, pages 325-331, 1991. // // Parameters: // // Input, int NODE_NUM, the number of nodes. // // Input, double NODE_XY[2*NODE_NUM], the coordinates of the nodes. // // Input, int TRIANGLE_ORDER, the order of the triangles. // // Input, int TRIANGLE_NUM, the number of triangles in the triangulation. // // Input, int TRIANGLE_NODE[TRIANGLE_ORDER*TRIANGLE_NUM], // the nodes of each triangle. // // Input, int TRIANGLE_NEIGHBOR[3*TRIANGLE_NUM], the triangle neighbor list. // // Input, double P[2], the coordinates of a point. // // Output, int *TRIANGLE, the index of the triangle where the search ended. // If a cycle occurred, then TRIANGLE = -1. // // Output, int *EDGE, indicates the position of the point (X,Y) in // triangle TRIANGLE: // 0, the interior or boundary of the triangle; // -1, outside the convex hull of the triangulation, past edge 1; // -2, outside the convex hull of the triangulation, past edge 2; // -3, outside the convex hull of the triangulation, past edge 3. // { int count = 0; edge = 0; int seed = RNG.nextint(); triangle = UniformRNG.i4_uniform(1, triangle_num, ref seed); for (;;) { count += 1; if (triangle_num < count) { Console.WriteLine(); Console.WriteLine("TRIANGULATION_SEARCH_DELAUNAY - Fatal error!"); Console.WriteLine(" The algorithm seems to be cycling."); Console.WriteLine(" Current triangle is " + triangle + ""); triangle = -1; edge = -1; return; } // // Get the vertices of triangle TRIANGLE. // int a = triangle_node[0 + (triangle - 1) * triangle_order] - 1; int b = triangle_node[1 + (triangle - 1) * triangle_order] - 1; int c = triangle_node[2 + (triangle - 1) * triangle_order] - 1; // // Using vertex C as a base, compute the distances to vertices A and B, // and the point (X,Y). // double dxa = node_xy[0 + a * 2] - node_xy[0 + c * 2]; double dya = node_xy[1 + a * 2] - node_xy[1 + c * 2]; double dxb = node_xy[0 + b * 2] - node_xy[0 + c * 2]; double dyb = node_xy[1 + b * 2] - node_xy[1 + c * 2]; double dxp = p[0 + pIndex] - node_xy[0 + c * 2]; double dyp = p[1 + pIndex] - node_xy[1 + c * 2]; double det = dxa * dyb - dya * dxb; // // Compute the barycentric coordinates of the point (X,Y) with respect // to this triangle. // double alpha = (dxp * dyb - dyp * dxb) / det; double beta = (dxa * dyp - dya * dxp) / det; double gamma = 1.0 - alpha - beta; // // If the barycentric coordinates are all positive, then the point // is inside the triangle and we're done. // if (0.0 <= alpha && 0.0 <= beta && 0.0 <= gamma) { break; } switch (alpha) { // // At least one barycentric coordinate is negative. // // If there is a negative barycentric coordinate for which there exists // an opposing triangle neighbor closer to the point, move to that triangle. // // (Two coordinates could be negative, in which case we could go for the // most negative one, or the most negative one normalized by the actual // distance it represents). // case < 0.0 when 0 <= triangle_neighbor[1 + (triangle - 1) * 3]: triangle = triangle_neighbor[1 + (triangle - 1) * 3]; continue; } switch (beta) { case < 0.0 when 0 <= triangle_neighbor[2 + (triangle - 1) * 3]: triangle = triangle_neighbor[2 + (triangle - 1) * 3]; continue; } switch (gamma) { case < 0.0 when 0 <= triangle_neighbor[0 + (triangle - 1) * 3]: triangle = triangle_neighbor[0 + (triangle - 1) * 3]; continue; } // // All negative barycentric coordinates correspond to vertices opposite // sides on the convex hull. // // Note the edge and exit. // if (alpha < 0.0) { edge = -2; break; } if (beta < 0.0) { edge = -3; break; } if (gamma < 0.0) { edge = -1; break; } Console.WriteLine(""); Console.WriteLine("TRIANGULATION_SEARCH - Fatal error!"); Console.WriteLine(" The algorithm seems to have reached a dead end"); Console.WriteLine(" after " + count + " steps."); triangle = -1; edge = -1; return; } }
private static void test06() //****************************************************************************80 // // Purpose: // // TEST06 tests LEVEL_SET; // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 05 January 2007 // // Author: // // John Burkardt // { int adj_num = 0; int i; int level_num = 0; int node_num = 0; int seed = 123456789; Console.WriteLine(""); Console.WriteLine("TEST06"); Console.WriteLine(" LEVEL_SET computes the level sets of a graph,"); Console.WriteLine(" given a root node (which defines level 1)."); Burkardt.Graph.Adjacency.graph_01_size(ref node_num, ref adj_num); int[] adj_row = new int[node_num + 1]; int[] adj = new int[adj_num]; Burkardt.Graph.Adjacency.graph_01_adj(node_num, adj_num, ref adj_row, ref adj); AdjacencyMatrix.adj_print(node_num, adj_num, adj_row, adj, " Adjacency matrix:"); AdjacencyMatrix.adj_show(node_num, adj_num, adj_row, adj); // // Choose different roots. // int[] level = new int[node_num]; int[] level_row = new int[node_num + 1]; int[] mask = new int[node_num]; for (i = 1; i <= 3; i++) { int root = UniformRNG.i4_uniform(1, node_num, ref seed); int j; for (j = 0; j < node_num; j++) { mask[j] = 1; } Burkardt.Graph.GenRCM.level_set(root, adj_num, adj_row, adj, ref mask, ref level_num, ref level_row, ref level, node_num); Burkardt.Graph.GenRCM.level_set_print(node_num, level_num, level_row, level); } }
public static double[] cluster_initialize_3(int dim_num, int point_num, int cluster_num, double[] point, ref int seed) //****************************************************************************80 // // Purpose: // // CLUSTER_INITIALIZE_3 initializes the cluster centers to random values. // // Discussion: // // In this case, each point is randomly assigned to a cluster, and // the cluster centers are then computed as the centroids of the points // in the cluster. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 08 October 2011 // // Author: // // John Burkardt // // Parameters: // // Input, int DIM_NUM, the number of spatial dimensions. // // Input, int POINT_NUM, the number of points. // // Input, int CLUSTER_NUM, the number of clusters. // // Input, double POINT[DIM_NUM*POINT_NUM], the coordinates // of the points. // // Input/output, int SEED, a seed for the random // number generator. // // Output, double CLUSTER_INITIALIZE_3[DIM_NUM*CLUSTER_NUM], // the coordinates of the cluster centers. // { int i; int j; int k; // // Assign one point to each cluster center. // double[] cluster_center = new double[dim_num * cluster_num]; for (k = 0; k < cluster_num; k++) { for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] = point[i + k * dim_num]; } } int[] cluster_population = new int[cluster_num]; for (k = 0; k < cluster_num; k++) { cluster_population[k] = 1; } // // The rest of the points get assigned randomly. // for (j = cluster_num; j < point_num; j++) { k = UniformRNG.i4_uniform(1, cluster_num, ref seed); for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] += point[i + j * dim_num]; } cluster_population[k] += 1; } // // Now average the points to get the centroid. // for (k = 0; k < cluster_num; k++) { if (cluster_population[k] == 0) { continue; } for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] /= cluster_population[k]; } } return(cluster_center); }
private static void test180() //****************************************************************************80 // // Purpose: // // TEST180 tests SORT_HEAP_EXTERNAL. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 29 April 2003 // // Author: // // John Burkardt // { const int N = 20; int[] a = new int[N]; Console.WriteLine(""); Console.WriteLine("TEST180"); Console.WriteLine(" SORT_HEAP_EXTERNAL sorts objects externally."); int indx = 0; int i; int j = 0; int isgn = 0; int seed = 123456789; for (i = 0; i < N; i++) { a[i] = UniformRNG.i4_uniform(1, N, ref seed); } typeMethods.i4vec_print(N, a, " Unsorted array:"); // // Call the sort routine over and over. // SortHeapExternalData data = new(); for (;;) { Sort.sort_heap_external(ref data, N, ref indx, ref i, ref j, isgn); // // If the return value of INDX is negative, we're asked to compare // array elements I and J; i %= a.Length; j %= a.Length; if (indx < 0) { if (a[i] <= a[j]) { isgn = -1; } else { isgn = 1; } } // // ...and if the return value of INDX is positive, we're asked to switch // array elements I and J; // else if (0 < indx) { typeMethods.i4_swap(ref a[i], ref a[j]); // // ...and if the return value of INDX is 0, we're done. // } else { break; } } typeMethods.i4vec_print(N, a, " Sorted array:"); }
public static void hmeans_w_02(int dim_num, int point_num, int cluster_num, int it_max, ref int it_num, double[] point, double[] weight, int[] cluster, double[] cluster_center, int[] cluster_population, double[] cluster_energy, ref int seed) //****************************************************************************80 // // Purpose: // // HMEANS_W_02 applies the weighted H-Means algorithm. // // Discussion: // // The input data for the weight H-Means problem includes: // * a set of N data points X in M dimensions, // * a set of N nonnegative weights W, // * a desired number of clusters K. // * an initial set of cluster centers Z, // * an (optional) initial set of cluster assignments. // // The goal is to determine K points Z, called cluster centers, and // to assign each point X(I) to some cluster Z(J), so that we minimize // the weighted standard deviation of the distance of each data point // to the center of its cluster. Writing J = CLUSTER(I) to // indicate the index of the nearest cluster center Z(J) to the // point X(I), the quantity we are trying to minimize is the sum // of the weighted cluster energies E(J), where: // // E(J) = Sum ( 1 <= I <= N ) W(I) * || X(I) - Z(J) ||^2 // // Here, we assume that we are using the Euclidean norm, so that // // || X(I) - Z(J) ||^2 = Sum ( 1 <= K <= M ) // ( X(I)(K) - Z(J)(K) )^2 // // In this notation, X(I)(K) is the K-th spatial component of the // I-th data point. // // Note that this routine should give the same results as HMEANS_02 // in any case in which all the entries of the WEIGHT vector are equal. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 09 October 2011 // // Author: // // John Burkardt // // Parameters: // // Input, int DIM_NUM, the number of spatial dimensions. // // Input, int POINT_NUM, the number of points. // // Input, int CLUSTER_NUM, the number of clusters. // // Input, int IT_MAX, the maximum number of iterations. // // Output, int &IT_NUM, the number of iterations taken. // // Input, double POINT[DIM_NUM*POINT_NUM], the coordinates // of the points. // // Input, double WEIGHT[POINT_NUM], the weights // assigned to the data points. These must be nonnegative, and // at least one must be strictly positive. // // Input/output, int CLUSTER[POINT_NUM]. On input, the user // may specify an initial cluster for each point, or leave all entrie of // CLUSTER set to 0. On output, CLUSTER contains the index of the // cluster to which each data point belongs. // // Input/output, double CLUSTER_CENTER[DIM_NUM*CLUSTER_NUM], // the coordinates of the cluster centers. // // Output, int CLUSTER_POPULATION[CLUSTER_NUM], the number of // points assigned to each cluster. // // Output, double CLUSTER_ENERGY[CLUSTER_NUM], the energy of // the clusters. // // Input/output, int *SEED, a seed for the random // number generator. // { int i; int j; int k; double point_energy; double point_energy_min; switch (cluster_num) { // // Data checks. // case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" CLUSTER_NUM < 1."); return; } switch (dim_num) { case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" DIM_NUM < 1."); return; } switch (point_num) { case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" POINT_NUM < 1."); return; } switch (it_max) { case < 0: Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" IT_MAX < 0."); return; } if (typeMethods.r8vec_any_negative(point_num, weight)) { Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" Some weight entry is negative."); return; } if (typeMethods.r8vec_all_nonpositive(point_num, weight)) { Console.WriteLine(""); Console.WriteLine("HMEANS_W_02 - Fatal error!"); Console.WriteLine(" No weight entry is positive."); return; } // // On input, legal entries in CLUSTER are preserved, but // otherwise, each point is assigned to its nearest cluster. // for (j = 0; j < point_num; j++) { if (cluster[j] >= 0 && cluster_num > cluster[j]) { continue; } point_energy_min = typeMethods.r8_huge(); for (k = 0; k < cluster_num; k++) { point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k * dim_num], 2); } if (!(point_energy < point_energy_min)) { continue; } point_energy_min = point_energy; cluster[j] = k; } } it_num = 0; for (;;) { // // Given centers, assign points to nearest center. // typeMethods.i4vec_zero(cluster_num, ref cluster_population); typeMethods.r8vec_zero(cluster_num, ref cluster_energy); double[] cluster_weight = typeMethods.r8vec_zero_new(cluster_num); int swap = 0; for (j = 0; j < point_num; j++) { point_energy_min = typeMethods.r8_huge(); k = cluster[j]; int k2; for (k2 = 0; k2 < cluster_num; k2++) { point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k2 * dim_num], 2); } if (!(point_energy < point_energy_min)) { continue; } point_energy_min = point_energy; cluster[j] = k2; } if (k != cluster[j]) { swap += 1; } k = cluster[j]; cluster_energy[k] += weight[j] * point_energy_min; cluster_population[k] += 1; cluster_weight[k] += weight[j]; } if (0 < it_num) { if (swap == 0) { break; } } if (it_max <= it_num) { break; } it_num += 1; // // Given points in cluster, replace center by weighted centroid. // typeMethods.r8vec_zero(dim_num * cluster_num, ref cluster_center); for (j = 0; j < point_num; j++) { k = cluster[j]; for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] += weight[j] * point[i + j * dim_num]; } } for (k = 0; k < cluster_num; k++) { if (cluster_weight[k] != 0.0) { for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] /= cluster_weight[k]; } } else { j = UniformRNG.i4_uniform(0, point_num - 1, ref seed); for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] = point[i + j * dim_num]; } } } } // // Compute the energy based on the final value of the cluster centers. // typeMethods.r8vec_zero(cluster_num, ref cluster_energy); for (j = 0; j < point_num; j++) { k = cluster[j]; point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k * dim_num], 2); } cluster_energy[k] += weight[j] * point_energy; } }
public static void hmeans_02(int dim_num, int point_num, int cluster_num, int it_max, ref int it_num, double[] point, int[] cluster, double[] cluster_center, int[] cluster_population, double[] cluster_energy, ref int seed) //****************************************************************************80 // // Purpose: // // HMEANS_02 applies the H-Means algorithm. // // Discussion: // // This is a simple routine to group a set of points into K clusters, // each with a center point, in such a way that the total cluster // energy is minimized. The total cluster energy is the sum of the // squares of the distances of each point to the center of its cluster. // // The algorithm begins with an initial estimate for the cluster centers: // // 1. The points are assigned to the nearest cluster centers. // // 2. The iteration exit ( 1 );s if the total energy has not changed // significantly, or we have reached the maximum number of iterations. // // 3. Each cluster center is replaced by the centroid of the points // in the cluster. // // 4. Return to step 1. // // The algorithm may fail to find the best solution. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 08 October 2011 // // Author: // // John Burkardt // // Parameters: // // Input, int DIM_NUM, the number of spatial dimensions. // // Input, int POINT_NUM, the number of points. // // Input, int CLUSTER_NUM, the number of clusters. // // Input, int IT_MAX, the maximum number of iterations. // // Output, int IT_NUM, the number of iterations taken. // // Input, double POINT[DIM_NUM*POINT_NUM], the coordinates // of the points. // // Input/output, int CLUSTER[POINT_NUM]. On input, the user // may specify an initial cluster for each point, or leave all entrie of // CLUSTER set to 0. On output, CLUSTER contains the index of the // cluster to which each data point belongs. // // Input/output, double CLUSTER_CENTER[DIM_NUM*CLUSTER_NUM], // the coordinates of the cluster centers. // // Output, int CLUSTER_POPULATION[CLUSTER_NUM], the number of // points assigned to each cluster. // // Output, double CLUSTER_ENERGY[CLUSTER_NUM], the energy of // the clusters. // // Input/output, int *SEED, a seed for the random // number generator. // { const bool debug = false; int i; int j; int k; double point_energy; double point_energy_min; switch (cluster_num) { // // Data checks. // case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_02 - Fatal error!"); Console.WriteLine(" CLUSTER_NUM < 1."); return; } switch (dim_num) { case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_02 - Fatal error!"); Console.WriteLine(" DIM_NUM < 1."); return; } switch (point_num) { case < 1: Console.WriteLine(""); Console.WriteLine("HMEANS_02 - Fatal error!"); Console.WriteLine(" POINT_NUM < 1."); return; } switch (it_max) { case < 0: Console.WriteLine(""); Console.WriteLine("HMEANS_02 - Fatal error!"); Console.WriteLine(" IT_MAX < 0."); return; } // // On input, legal entries in CLUSTER are preserved, but // otherwise, each point is assigned to its nearest cluster. // for (j = 0; j < point_num; j++) { if (cluster[j] >= 0 && cluster_num > cluster[j]) { continue; } point_energy_min = typeMethods.r8_huge(); for (k = 0; k < cluster_num; k++) { point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k * dim_num], 2); } if (!(point_energy < point_energy_min)) { continue; } point_energy_min = point_energy; cluster[j] = k; } } it_num = 0; for (;;) { // // Given centers, assign points to nearest center. // typeMethods.i4vec_zero(cluster_num, ref cluster_population); typeMethods.r8vec_zero(cluster_num, ref cluster_energy); int swap = 0; for (j = 0; j < point_num; j++) { point_energy_min = typeMethods.r8_huge(); k = cluster[j]; int k2; for (k2 = 0; k2 < cluster_num; k2++) { point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k2 * dim_num], 2); } if (!(point_energy < point_energy_min)) { continue; } point_energy_min = point_energy; cluster[j] = k2; } if (k != cluster[j]) { swap += 1; } k = cluster[j]; cluster_energy[k] += point_energy_min; cluster_population[k] += 1; } switch (debug) { case true: Console.WriteLine(" " + it_num.ToString(CultureInfo.InvariantCulture).PadLeft(3) + " " + typeMethods.r8vec_sum(cluster_num, cluster_energy).ToString(CultureInfo.InvariantCulture) .PadLeft(14) + ""); break; } if (0 < it_num) { if (swap == 0) { break; } } if (it_max <= it_num) { break; } it_num += 1; // // Given points in cluster, replace center by centroid. // typeMethods.r8vec_zero(dim_num * cluster_num, ref cluster_center); for (j = 0; j < point_num; j++) { k = cluster[j]; for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] += point[i + j * dim_num]; } } for (k = 0; k < cluster_num; k++) { if (cluster_population[k] != 0) { for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] /= cluster_population[k]; } } else { j = UniformRNG.i4_uniform(0, point_num - 1, ref seed); for (i = 0; i < dim_num; i++) { cluster_center[i + k * dim_num] = point[i + j * dim_num]; } } } } // // Compute the energy based on the final value of the cluster centers. // typeMethods.r8vec_zero(cluster_num, ref cluster_energy); for (j = 0; j < point_num; j++) { k = cluster[j]; point_energy = 0.0; for (i = 0; i < dim_num; i++) { point_energy += Math.Pow(point[i + j * dim_num] - cluster_center[i + k * dim_num], 2); } cluster_energy[k] += point_energy; } }