public IClusteringCentroid <DomainType> Cluster(IDataSet <DomainType> data_set)
        {
            IFunction <IList <DomainType[]>, ICentroidDistance <DomainType> > centroid_calculator = centroid_calculator_template.Generate(data_set.DataContext);
            IList <DomainType[]>  instance_features_list = data_set.FeatureData;
            RandomNumberGenerator generator = new RNGCryptoServiceProvider();
            IList <ICentroidDistance <DomainType> > centroids = new List <ICentroidDistance <DomainType> >();

            int[] permutation = generator.RandomPermutation(instance_features_list.Count);

            for (int centroid_index = 0; centroid_index < this.desired_cluster_count; centroid_index++)
            {
                IList <DomainType[]> centroid_members = new List <DomainType[]>();
                centroid_members.Add(instance_features_list[permutation[centroid_index]]);

                if (centroid_members.Count != 0)
                {
                    centroids.Add(centroid_calculator.Compute(centroid_members));
                }
            }

            Cluster(instance_features_list, centroid_calculator, centroids);
            return(new ClusteringCentroid <DomainType>(data_set.DataContext, centroids));
        }
        public IClusteringCentroid <DomainType> Cluster(IDataSet <DomainType> data_set)
        {
            IFunction <IList <DomainType[]>, ICentroidDistance <DomainType> > centroid_calculator = centroid_calculator_template.Generate(data_set.DataContext);
            IList <DomainType[]>                    instance_features_list = data_set.FeatureData;
            IList <IList <DomainType[]> >           cluster_members        = new List <IList <DomainType[]> >();
            IList <ICentroidDistance <DomainType> > centroids = new List <ICentroidDistance <DomainType> >();

            // add first cluster
            cluster_members.Add(new List <DomainType[]>());
            cluster_members[0].Add(instance_features_list[0]);
            centroids.Add(centroid_calculator.Compute(cluster_members[0]));

            // assign to clusters
            for (int index_instance = 1; index_instance < instance_features_list.Count; index_instance++)
            {
                DomainType[] instance_features = instance_features_list[index_instance];

                int    best_cluster_index = 0;
                double best_distance      = centroids[0].ComputeDistance(instance_features);

                for (int cluster_index = 1; cluster_index < centroids.Count; cluster_index++)
                {
                    double distance = centroids[cluster_index].ComputeDistance(instance_features);

                    if (distance.CompareTo(best_distance) == 1)
                    {
                        best_distance      = distance;
                        best_cluster_index = cluster_index;
                    }
                }

                if (best_distance.CompareTo(critical_distance) == 1)
                {
                    // create new cluster
                    IList <DomainType[]> new_cluster = new List <DomainType[]>();
                    new_cluster.Add(instance_features);
                    cluster_members.Add(new_cluster);
                    centroids.Add(centroid_calculator.Compute(new_cluster));
                }
                else
                {
                    // add to existing cluster and recompute centroid
                    cluster_members[best_cluster_index].Add(instance_features);
                    centroids[best_cluster_index] = centroid_calculator.Compute(cluster_members[best_cluster_index]);
                }
            }

            return(new ClusteringCentroid <DomainType>(data_set.DataContext, centroids));
        }