/**
         * @param Clustering
         *            The array of clusters
         * @param posi
         *            The index of the merged cluster
         * @param posj
         *            The index of the cluster that will be eliminated from the
         *            clustering
         * @param distance
         *            The distance matrix that will be updated
         */
        void UpdateDistances(List <SpeakerCluster> clustering, int posi, int posj, Array2DRowRealMatrix distance)
        {
            int clusterCount = clustering.Count;

            for (int i = 0; i < clusterCount; i++)
            {
                distance.setEntry(i, posi, ComputeDistance(clustering[i], clustering[posi]));
                distance.setEntry(posi, i, distance.getEntry(i, posi));
            }
            for (int i = posj; i < clusterCount - 1; i++)
            {
                for (int j = 0; j < clusterCount; j++)
                {
                    distance.setEntry(i, j, distance.getEntry(i + 1, j));
                }
            }

            for (int i = 0; i < clusterCount; i++)
            {
                for (int j = posj; j < clusterCount - 1; j++)
                {
                    distance.setEntry(i, j, distance.getEntry(i, j + 1));
                }
            }
        }
 internal virtual void printMatrix(Array2DRowRealMatrix array2DRowRealMatrix)
 {
     for (int i = 0; i < array2DRowRealMatrix.getRowDimension(); i++)
     {
         for (int j = 0; j < array2DRowRealMatrix.getColumnDimension(); j++)
         {
             [email protected](new StringBuilder().append(array2DRowRealMatrix.getEntry(i, j)).append(" ").toString());
         }
         [email protected]();
     }
 }
 void PrintMatrix(Array2DRowRealMatrix a)
 {
     for (int i = 0; i < a.getRowDimension(); i++)
     {
         for (int j = 0; j < a.getColumnDimension(); j++)
         {
             Console.Write(a.getEntry(i, j) + " ");
         }
         Console.WriteLine();
     }
 }
        internal virtual void updateDistances(ArrayList arrayList, int num, int num2, Array2DRowRealMatrix array2DRowRealMatrix)
        {
            int num3 = arrayList.size();

            for (int i = 0; i < num3; i++)
            {
                array2DRowRealMatrix.setEntry(i, num, this.computeDistance((SpeakerCluster)arrayList.get(i), (SpeakerCluster)arrayList.get(num)));
                array2DRowRealMatrix.setEntry(num, i, array2DRowRealMatrix.getEntry(i, num));
            }
            for (int i = num2; i < num3 - 1; i++)
            {
                for (int j = 0; j < num3; j++)
                {
                    array2DRowRealMatrix.setEntry(i, j, array2DRowRealMatrix.getEntry(i + 1, j));
                }
            }
            for (int i = 0; i < num3; i++)
            {
                for (int j = num2; j < num3 - 1; j++)
                {
                    array2DRowRealMatrix.setEntry(i, j, array2DRowRealMatrix.getEntry(i, j + 1));
                }
            }
        }
        internal virtual Array2DRowRealMatrix updateDistances(ArrayList arrayList)
        {
            int num = arrayList.size();
            Array2DRowRealMatrix array2DRowRealMatrix = new Array2DRowRealMatrix(num, num);

            for (int i = 0; i < num; i++)
            {
                for (int j = 0; j <= i; j++)
                {
                    array2DRowRealMatrix.setEntry(i, j, this.computeDistance((SpeakerCluster)arrayList.get(i), (SpeakerCluster)arrayList.get(j)));
                    array2DRowRealMatrix.setEntry(j, i, array2DRowRealMatrix.getEntry(i, j));
                }
            }
            return(array2DRowRealMatrix);
        }
        /**
         * @param Clustering
         *            The array of clusters
         */
        Array2DRowRealMatrix UpdateDistances(List <SpeakerCluster> clustering)
        {
            int clusterCount = clustering.Count;
            Array2DRowRealMatrix distance = new Array2DRowRealMatrix(clusterCount, clusterCount);

            for (int i = 0; i < clusterCount; i++)
            {
                for (int j = 0; j <= i; j++)
                {
                    distance.setEntry(i, j, ComputeDistance(clustering[i], clustering[j]));
                    distance.setEntry(j, i, distance.getEntry(i, j));
                }
            }
            return(distance);
        }
        /**
         * @param features The feature vectors to be used for clustering
         * @return A cluster for each speaker detected based on the feature vectors provided
         */
        public List <SpeakerCluster> Cluster(List <float[]> features)
        {
            List <SpeakerCluster> ret            = new List <SpeakerCluster>();
            Array2DRowRealMatrix  featuresMatrix = ArrayToRealMatrix(features, features.Count);
            LinkedList <Integer>  l = GetAllChangingPoints(featuresMatrix);
            var it = l.GetEnumerator();
            int curent;

            it.MoveNext();
            int previous = it.Current;

            while (it.MoveNext())
            {
                curent = it.Current;
                Segment s = new Segment(previous * Segment.FrameLength, (curent - previous)
                                        * (Segment.FrameLength));
                Array2DRowRealMatrix featuresSubset = (Array2DRowRealMatrix)featuresMatrix.getSubMatrix(
                    previous, curent - 1, 0, 12);
                ret.Add(new SpeakerCluster(s, featuresSubset, GetBICValue(featuresSubset)));
                previous = curent;
            }
            int clusterCount = ret.Count;

            Array2DRowRealMatrix distance;

            distance = new Array2DRowRealMatrix(clusterCount, clusterCount);
            distance = UpdateDistances(ret);
            while (true)
            {
                double distmin = 0;
                int    imin = -1, jmin = -1;

                for (int i = 0; i < clusterCount; i++)
                {
                    for (int j = 0; j < clusterCount; j++)
                    {
                        if (i != j)
                        {
                            distmin += distance.getEntry(i, j);
                        }
                    }
                }
                distmin /= (clusterCount * (clusterCount - 1) * 4);

                for (int i = 0; i < clusterCount; i++)
                {
                    for (int j = 0; j < clusterCount; j++)
                    {
                        if (distance.getEntry(i, j) < distmin && i != j)
                        {
                            distmin = distance.getEntry(i, j);
                            imin    = i;
                            jmin    = j;
                        }
                    }
                }
                if (imin == -1)
                {
                    break;
                }
                ret[imin].MergeWith(ret[jmin]);
                UpdateDistances(ret, imin, jmin, distance);
                ret.Remove(jmin);
                clusterCount--;
            }
            return(ret);
        }