public static void cvt(ref LCVData data, int m, int n, int sample_function_init, int sample_function_cvt, int sample_num_cvt, int maxit, ref int seed, ref double[] generator) //****************************************************************************80 // // Purpose: // // CVT computes a Centroidal Voronoi Tessellation. // // Discussion: // // The routine is given a set of points, called "generators", which // define a tessellation of the region into Voronoi cells. Each point // defines a cell. Each cell, in turn, has a centroid, but it is // unlikely that the centroid and the generator coincide. // // Each time this CVT iteration is carried out, an attempt is made // to modify the generators in such a way that they are closer and // closer to being the centroids of the Voronoi cells they generate. // // A large number of sample points are generated, and the nearest generator // is determined. A count is kept of how many points were nearest to each // generator. Once the sampling is completed, the location of all the // generators is adjusted. This step should decrease the discrepancy // between the generators and the centroids. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 05 May 2003 // // Author: // // John Burkardt // // Parameters: // // Input, int M, the spatial dimension. // // Input, int N, the number of Voronoi cells. // // Input, int SAMPLE_FUNCTION_INIT, generator initialization function: // -1, initializing function is RANDOM (C++ STDLIB library function); // 0, initializing function is UNIFORM; // 1, initializing function is HALTON; // 2, initializing function is GRID; // 3, initial values are set by the user. // // Input, int SAMPLE_FUNCTION_CVT, region sampling function: // -1, sampling function is RANDOM (C++ STDLIB library function); // 0, sampling function is UNIFORM; // 1, sampling function is HALTON; // 2, sampling function is GRID; // // Input, int SAMPLE_NUM_CVT, the number of sample points. // // Input, int MAXIT, the maximum number of correction iterations // used in the Voronoi calculation. // // Input/output, int *SEED, the random number seed. // // Input/output, double GENERATOR[M*N], the Voronoi cell generators. // On input, if SAMPLE_FUNCTION_INIT = 3, the user has initialized these. // On output, the values have been through the CVT iteration. // { double change_l2 = 0; int it; const bool verbose = true; // // Initialize the generators. // if (sample_function_init != 3) { const bool reset = true; Region.region_sampler(ref data.data, m, n, n, ref generator, sample_function_init, reset, ref seed); } switch (verbose) { // // Carry out the iteration. // case true: Console.WriteLine(""); Console.WriteLine(" STEP L2 Change"); Console.WriteLine(""); break; } for (it = 1; it <= maxit; it++) { cvt_iteration(ref data, m, n, ref generator, sample_num_cvt, sample_function_cvt, ref seed, ref change_l2); switch (verbose) { case true: Console.WriteLine(it.ToString(CultureInfo.InvariantCulture).PadLeft(4) + " " + change_l2.ToString(CultureInfo.InvariantCulture).PadLeft(12) + ""); break; } } }
public static void cvt_iteration(ref LCVData data, int m, int n, ref double[] generator, int sample_num_cvt, int sample_function_cvt, ref int seed, ref double change_l2) //****************************************************************************80 // // Purpose: // // CVT_ITERATION takes one step of the CVT iteration. // // Discussion: // // The routine is given a set of points, called "generators", which // define a tessellation of the region into Voronoi cells. Each point // defines a cell. Each cell, in turn, has a centroid, but it is // unlikely that the centroid and the generator coincide. // // Each time this CVT iteration is carried out, an attempt is made // to modify the generators in such a way that they are closer and // closer to being the centroids of the Voronoi cells they generate. // // A large number of sample points are generated, and the nearest generator // is determined. A count is kept of how many points were nearest to each // generator. Once the sampling is completed, the location of all the // generators is adjusted. This step should decrease the discrepancy // between the generators and the centroids. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 05 May 2003 // // Author: // // John Burkardt // // Parameters: // // Input, int M, the spatial dimension. // // Input, int N, the number of Voronoi cells. // // Input/output, double GENERATOR[M*N], the Voronoi // cell generators. On output, these have been modified // // Input, int SAMPLE_NUM_CVT, the number of sample points. // // Input, int SAMPLE_FUNCTION_CVT, region sampling function: // -1, sampling function is RANDOM (C++ STDLIB library function); // 0, sampling function is UNIFORM; // 1, sampling function is HALTON; // 2, sampling function is GRID; // // Input/output, int *SEED, the random number seed. // // Output, double *CHANGE_L2, the L2 norm of the difference between // the input and output data. // { int i; int j; int k; // double[] generator2 = new double[m * n]; for (k = 0; k < m * n; k++) { generator2[k] = 0.0; } int[] count = new int[n]; for (i = 0; i < n; i++) { count[i] = 0; } double[] x = new double[m]; bool reset = true; seed = sample_function_cvt switch { // // If we are using the C++ random number generator, then initialize using the current seed. // (Currently, if we are using RANDOM for both the initializing and sampling, we make this // call twice, which is inefficient and possibly misleading.) // -1 => entropyRNG.RNG.nextint(), _ => seed }; for (j = 0; j < sample_num_cvt; j++) { // // Generate a sampling point X. // Region.region_sampler(ref data.data, m, 1, sample_num_cvt, ref x, sample_function_cvt, reset, ref seed); reset = false; // // Find the nearest cell generator. // int nearest = find_closest(m, n, x, generator); // // Add X to the averaging data for GENERATOR(*,NEAREST). // for (i = 0; i < m; i++) { generator2[nearest * m + i] += x[i]; } count[nearest] += 1; } // // Compute the new generators. // for (j = 0; j < n; j++) { if (count[j] == 0) { continue; } for (i = 0; i < m; i++) { generator2[j * m + i] /= count[j]; } } // // Determine the change. // change_l2 = 0.0; for (k = 0; k < m * n; k++) { change_l2 += Math.Pow(generator2[k] - generator[k], 2); } change_l2 = Math.Sqrt(change_l2); // // Update. // for (k = 0; k < m * n; k++) { generator[k] = generator2[k]; } }