public void Test_UpdateMax()
 {
     double[] max = new double[2].Fill(double.MinValue);
     VectorS.UpdateMax(new double[] { 1, 3 }, max);
     Assert.AreEqual(new double[] { 1, 3 }, max);
     VectorS.UpdateMax(new double[] { 5, 0.4 }, max);
     Assert.AreEqual(new double[] { 5, 3 }, max);
 }
        /// <summary>
        /// Run k-means.
        /// Returns hand values.
        /// </summary>
        protected double[][] CalcValuesAndKMeans(KMeansNode parentKmNode, int round, McHand[] hands, out double[][] centers)
        {
            double [][] values = new double[hands.Length][].Fill(i => new double[Dim]);

            double[] min = new double[Dim].Fill(double.MaxValue);
            double[] max = new double[Dim].Fill(double.MinValue);

            for (int i = 0; i < hands.Length; ++i)
            {
                CalculateValue(hands[i].Cards, hands[i].Length, values[i]);
                VectorS.UpdateMin(values[i], min);
                VectorS.UpdateMax(values[i], max);
            }
            double [] delta = VectorS.Sub(max, min);

            if (_normalizeHandValues)
            {
                for (int i = 0; i < values.Length; ++i)
                {
                    VectorS.NormalizeByDiff(values[i], min, delta);
                }
                min.CopyTo(parentKmNode.ValueMin, 0);
                delta.CopyTo(parentKmNode.ValueBounds, 0);
            }

            if (_printHandValues || _printHands)
            {
                for (int i = 0; i < values.Length; ++i)
                {
                    if (_printHands)
                    {
                        Console.Write("{0} ", StdDeck.Descriptor.GetCardNames(hands[i].Cards, 0, hands[i].Length));
                    }
                    if (_printHandValues)
                    {
                        PrintVector(values[i]);
                    }
                    Console.WriteLine();
                }
            }

            // Calcualate number of clusters.
            int k           = MaxBucketCounts[round];
            int adaptingDim = -1;

            for (int d = 0; d < Dim; ++d)
            {
                double clusterSize = ClusterSizes[d][round];
                if (clusterSize != 0)
                {
                    int clCount = (int)Math.Round(delta[d] / clusterSize, 0);
                    if (clCount < k)
                    {
                        adaptingDim = d;
                        k           = clCount;
                    }
                }
            }
            // Make sure number of clusters is in the given range.
            k = Math.Max(MinBucketCounts[round], k);

            if (IsVerbose)
            {
                Console.Write("Min: ");
                PrintVector(min);
                Console.Write(" Max: ");
                PrintVector(max);
                Console.Write(" Delta: ");
                PrintVector(delta);
                if (k < MaxBucketCounts[round])
                {
                    Console.Write(" K adapted to {0} by dim: {1}", k, adaptingDim);
                }
                Console.WriteLine();
            }

            double [][] differentValues      = new double[k][].Fill(i => new double[Dim]);
            int         differentValuesCount = 0;

            for (int i = 0; i < values.Length; ++i)
            {
                for (int j = 0; j < differentValuesCount; ++j)
                {
                    if (VectorS.AreEqual(values[i], differentValues[j]))
                    {
                        goto RepeatedValue;
                    }
                }
                values[i].CopyTo(differentValues[differentValuesCount], 0);
                differentValuesCount++;
                if (differentValuesCount == k)
                {
                    break;
                }
                RepeatedValue :;
            }
            if (differentValuesCount < k)
            {
                // Too few different values to build k clusters. Do not run k-means, it may hang.
                centers = differentValues;
                Array.Resize(ref centers, differentValuesCount);
                if (IsVerbose)
                {
                    Console.WriteLine("Only {0} different values found. Set cluster count, do not run kmeans", differentValuesCount);
                }
                return(values);
            }

            _kmParameters.k = k;
            _kmParameters.n = values.Length;

            _kmParameters.Allocate();

            for (int i = 0; i < values.Length; ++i)
            {
                for (int d = 0; d < Dim; ++d)
                {
                    *_kmParameters.GetPoint(i, d) = values[i][d];
                }
            }

            fixed(Kml.Parameters *kmlp = &_kmParameters)
            {
                Kml.KML_Hybrid(kmlp);
            }

            centers = new double[_kmParameters.k][].Fill(i => new double[Dim]);
            for (int c = 0; c < _kmParameters.k; ++c)
            {
                for (int d = 0; d < Dim; ++d)
                {
                    centers[c][d] = *_kmParameters.GetCenter(c, d);
                }
            }
            _kmParameters.Free();

            return(values);
        }