Beispiel #1
0
        public void minimize_test()
        {
            #region doc_example
            // This is the same example that is found in Wikipedia:
            // https://en.wikipedia.org/wiki/Hungarian_algorithm

            double[][] costMatrix =
            {
                //                      Clean bathroom, Sweep floors,  Wash windows
                /* Armond   */ new double[] { 2, 3, 3 },
                /* Francine */ new double[] { 3, 2, 3 },
                /* Herbert  */ new double[] { 3, 3, 2 },
            };

            // Create a new Hungarian algorithm
            Munkres m = new Munkres(costMatrix);

            bool     success     = m.Minimize(); // solve it (should return true)
            double[] solution    = m.Solution;   // Solution will be 0, 1, 2
            double   minimumCost = m.Value;      // should be 6
            #endregion

            Assert.AreEqual(3, m.NumberOfTasks);
            Assert.AreEqual(3, m.NumberOfWorkers);

            Assert.IsTrue(success);
            Assert.AreEqual(6, minimumCost);
            Assert.AreEqual(0, solution[0]);
            Assert.AreEqual(1, solution[1]);
            Assert.AreEqual(2, solution[2]);
        }
Beispiel #2
0
        public void minimize_test_more_workers()
        {
            // A = [ 1 2 3; 2 4 6; 3 6 9; 4 8 12 ]
            double[][] costMatrix =
            {
                new double[] { 1, 2,  3 },
                new double[] { 2, 4,  6 },
                new double[] { 3, 6,  9 },
                new double[] { 4, 8, 12 },
            };

            var m = new Munkres(costMatrix);

            Assert.AreEqual(3, m.NumberOfTasks);
            Assert.AreEqual(4, m.NumberOfWorkers);

            bool success = m.Minimize();

            Assert.AreEqual(3, m.validCol.Length);
            Assert.AreEqual(4, m.validRow.Length);

            Assert.IsTrue(success);
            Assert.AreEqual(10, m.Value);
            Assert.IsTrue(m.starZ.IsEqual(new[] { 2, 1, 0, 3 }));
            Assert.IsTrue(m.Solution.IsEqual(new[] { 2, 1, 0, Double.NaN }));
        }
//WIP solve using the hungarian problem
        public BigInteger fitn(int[] container, int[] box)
        {
            double[][] hungarianGrid = new double[container.Length][];


            for (int i = 0; i < box.Length; i++)
            {
                hungarianGrid[i] = new double[box.Length];
            }

            for (int y = 0; y < container.Length; y++)
            {
                for (int x = 0; x < box.Length; x++)
                {
                    //Console.Write(container[x]);
                    hungarianGrid[x][y] = container[x] % box[y];

                    Console.Write(hungarianGrid[x][y] + " ");
                }
                Console.WriteLine();
            }
            //row reduction
            Munkres munkresSolution = new Munkres(hungarianGrid);

            munkresSolution.Minimize();

            for (int y = 0; y < container.Length; y++)
            {
                for (int x = 0; x < box.Length; x++)
                {
                    //Console.Write(container[x]);


                    Console.Write(hungarianGrid[x][y] + " ");
                }
                Console.WriteLine();
            }
            double[] values = munkresSolution.Solution;
            foreach (int i in values)
            {
                Console.WriteLine(i + " ");
            }

            BigInteger answer = 1;

            for (int i = 0; i < container.Length; i++)
            {
                Console.WriteLine("Container: " + container[i] + " Box: " + box[(int)values[i]] + "Answer: " + (container[i] / box[(int)values[i]]));
                answer *= (container[i] / box[(int)values[i]]);
            }

            return(answer);
        }
Beispiel #4
0
        private void LancerRepartition(int[,] matrice)
        {
            DateTime start = DateTime.Now;

            NbParProjet = new int[NbProjets];
            //Creation de la matrice
            //CreerMatrice(matrice);
            RetirerZero(matrice);
            //AfficherMatrice(Conversion(matrice));
            MatriceBase = Conversion(matrice);
            bool suppression = true;
            bool echec       = false;
            int  i           = 0;

            while (suppression)
            {
                //Initialisation
                NbParProjet = new int[NbProjets];
                suppression = EquilibrageProjetsMedian(i);
                //suppression = SupprimerProjet(i);
                Matrice  = (double[][])MatriceBase.Clone();
                ProjetsD = (string[])Projets.Clone();
                Matrice  = DupliquerVoeux(Matrice);

                //Repartition
                if (!suppression)
                {
                    if (i == 1)
                    {
                        echec = true;
                        MessageBox.Show("Problème dans les paramètres de répartition. Vérifiez qu'il y a assez de place pour chaque élève, ou qu'il n'y a pas trop de projets obligatoires.");
                    }
                    break;
                }
                Munkres repartition;
                bool    succes;
                repartition = new Munkres(Matrice);
                succes      = repartition.Minimize();
                //AfficherSolution(repartition.Solution);
                //Ecriture
                EcrireCsv(Matrice, repartition.Solution, i);


                //MessageBox.Show("Solution n°"+(i+1)+" : CHECK");
                i++;
            }
            TimeSpan dur = DateTime.Now - start;

            MessageBox.Show("La répartition a bien été effectuée ! Vous avez le choix entre " + i + " solutions différentes.");
        }
Beispiel #5
0
        public void minimize_test2()
        {
            double[][] costMatrix = Jagged.Magic(5);

            var m = new Munkres(costMatrix);

            Assert.AreEqual(5, m.NumberOfTasks);
            Assert.AreEqual(5, m.NumberOfWorkers);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(15, m.Value);
            Assert.AreEqual(2, m.Solution[0]);
            Assert.AreEqual(1, m.Solution[1]);
            Assert.AreEqual(0, m.Solution[2]);
            Assert.AreEqual(4, m.Solution[3]);
            Assert.AreEqual(3, m.Solution[4]);
        }
Beispiel #6
0
        public void large_test_2()
        {
            double[,] costMatrix =
            {
                { 3.2659e+003, 1.8662e+003, 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003 },
                { 1.6339e-012, 4.6656e+002, 1.3997e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003 },
                { 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003 },
                { 1.8662e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003 },
                { 3.2659e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003 },
                { 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003 },
                { 3.2659e+003, 1.8662e+003, 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003 },
                { 1.6339e-012, 4.6656e+002, 1.3997e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003 },
                { 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003 },
                { 1.8662e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003 },
                { 3.2659e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003 },
                { 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003 },
                { 3.2659e+003, 1.8662e+003, 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003 },
                { 1.6339e-012, 4.6656e+002, 1.3997e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003 },
                { 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003 },
                { 1.8662e+003, 1.3997e+003, 4.6656e+002, 1.6339e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 4.6656e+002, 4.6656e+002, 1.3997e+003, 1.8662e+003, 3.2659e+003 },
                { 3.2659e+003, 4.1990e+003, 3.2659e+003, 1.3997e+003, 4.6656e+002, 1.3997e+003, 3.2659e+003, 5.5987e+003, 6.0653e+003, 7.4650e+003, 6.0653e+003, 5.5987e+003, 3.2659e+003, 1.8662e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.8662e+003 },
                { 4.6656e+002, 4.6656e+002, 1.8662e+003, 3.2659e+003, 3.2659e+003, 1.8662e+003, 1.3997e+003, 4.6656e+002, 6.5358e-012, 4.6656e+002, 1.3997e+003, 3.2659e+003, 4.1990e+003, 6.0653e+003, 5.5987e+003, 6.0653e+003, 4.1990e+003, 3.2659e+003 }
            };

            Munkres m = new Munkres(costMatrix.ToJagged());

            Assert.AreEqual(18, m.NumberOfTasks);
            Assert.AreEqual(18, m.NumberOfWorkers);
            Assert.AreEqual(18 * 18, m.NumberOfVariables);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(6998.4200000000255, m.Value, 1e-5);

            int[] expected = { 3, 18, 2, 4, 17, 8, 12, 6, 10, 14, 15, 9, 13, 7, 11, 5, 16, 1 };

            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i] - 1, m.Solution[i]);
            }
        }
Beispiel #7
0
        public void large_test_1()
        {
            double[][] costMatrix =
            {
                new[] { 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000 },
                new[] { 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000 },
                new[] { 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000 },
                new[] { 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000 },
                new[] { 3265.92000000000, 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000 },
                new[] { 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000 },
                new[] { 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000 },
                new[] { 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000 },
                new[] { 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000 },
                new[] { 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000 },
                new[] { 3265.92000000000, 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000 },
                new[] { 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000 },
                new[] { 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000 },
                new[] { 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000 },
                new[] { 466.560000000000, 1399.68000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000 },
                new[] { 1866.24000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 3265.92000000000, 1866.24000000000, 1399.68000000000, 466.560000000000, 466.560000000000, 466.560000000000, 1399.68000000000, 1866.24000000000, 3265.92000000000 },
                new[] { 3265.92000000000, 1399.68000000000, 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000 },
                new[] { 466.560000000000, 1399.68000000000, 3265.92000000000, 4199.04000000000, 3265.92000000000, 1399.68000000000, 466.560000000000, 0.00000000000000, 466.560000000000, 1866.24000000000, 3265.92000000000, 5598.72000000000, 6065.28000000000, 7464.96000000000, 6065.28000000000, 5598.72000000000, 3265.92000000000, 1866.24000000000 },
            };

            Munkres m = new Munkres(costMatrix);

            Assert.AreEqual(18, m.NumberOfTasks);
            Assert.AreEqual(18, m.NumberOfWorkers);
            Assert.AreEqual(18 * 18, m.NumberOfVariables);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(7931.5200000000032, m.Value);

            int[] expected = { 1, 2, 18, 14, 13, 7, 5, 10, 17, 4, 12, 8, 6, 11, 16, 15, 3, 9 };

            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i] - 1, m.Solution[i]);
            }
        }
Beispiel #8
0
        public void minimize_test_more_jobs()
        {
            double[][] costMatrix =
            {
                new double[] { 1, 2, 3,  4 },
                new double[] { 2, 4, 6,  8 },
                new double[] { 3, 6, 9, 12 },
            };

            var m = new Munkres(costMatrix);

            Assert.AreEqual(4, m.NumberOfTasks);
            Assert.AreEqual(3, m.NumberOfWorkers);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(10, m.Value);
            Assert.AreEqual(2, m.Solution[0]);
            Assert.AreEqual(1, m.Solution[1]);
            Assert.AreEqual(0, m.Solution[2]);
        }
Beispiel #9
0
        public void minimize_invalid_row()
        {
            double inf = Double.PositiveInfinity;

            double[][] costMatrix =
            {
                new double[] { 1.0, inf, inf, inf },
                new double[] { 3.0, inf, inf, inf },
                new double[] { 1.0, inf, 5.0, 0.5 },
            };

            var m = new Munkres(costMatrix);

            Assert.AreEqual(3, m.NumberOfTasks);
            Assert.AreEqual(3, m.NumberOfWorkers);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(1.5, m.Value);
            Assert.IsTrue(m.starZ.IsEqual(new[] { 0, 1, 2 }));
            Assert.IsTrue(m.Solution.IsEqual(new[] { 0, Double.NaN, 2 }));
        }
Beispiel #10
0
        public void minimize_test3()
        {
            // http://csclab.murraystate.edu/~bob.pilgrim/445/munkres.html

            double[][] costMatrix =
            {
                new double[] { 1, 2, 3 },
                new double[] { 2, 4, 6 },
                new double[] { 3, 6, 9 },
            };

            var m = new Munkres(costMatrix);

            Assert.AreEqual(3, m.NumberOfTasks);
            Assert.AreEqual(3, m.NumberOfWorkers);

            bool success = m.Minimize();

            Assert.IsTrue(success);
            Assert.AreEqual(10, m.Value);
            Assert.AreEqual(2, m.Solution[0]);
            Assert.AreEqual(1, m.Solution[1]);
            Assert.AreEqual(0, m.Solution[2]);
        }
Beispiel #11
0
        /// <summary>
        ///   Learns a model that can map the given inputs to the desired outputs. Note:
        ///   the model created by this function will not be able to produce balanced
        ///   clusterings. To retrieve the balanced labels, check the <see cref="Labels"/>
        ///   property of this class after calling this function.
        /// </summary>
        ///
        /// <param name="x">The model inputs.</param>
        /// <param name="weights">The weight of importance for each input sample.</param>
        ///
        /// <returns>A model that has learned how to produce suitable outputs
        ///   given the input data <paramref name="x" />.</returns>
        ///
        public override KMeansClusterCollection Learn(double[][] x, double[] weights = null)
        {
            // Initial argument checking
            if (MaxIterations == 0)
            {
                throw new InvalidOperationException("MaxIterations must be higher than zero. The Balanced K-Means algorithm has a high chance of oscillating between possible answers without converging.");
            }

            if (x == null)
            {
                throw new ArgumentNullException("x");
            }

            if (x.Length < K)
            {
                throw new ArgumentException("Not enough points. There should be more points than the number K of clusters.");
            }

            if (weights == null)
            {
                weights = Vector.Ones(x.Length);
            }
            else
            {
                if (x.Length != weights.Length)
                {
                    throw new ArgumentException("Data weights vector must be the same length as data samples.");
                }
            }

            double weightSum = weights.Sum();

            if (weightSum <= 0)
            {
                throw new ArgumentException("Not enough points. There should be more points than the number K of clusters.");
            }

            if (!x.IsRectangular())
            {
                throw new DimensionMismatchException("data", "The points matrix should be rectangular. The vector at position {} has a different length than previous ones.");
            }

            int k    = this.K;
            int rows = x.Length;
            int cols = x[0].Length;

            // Perform some iterations of the original k-Means
            // algorithm if the model has not been initialized
            //
            if (this.Clusters.Centroids[0] == null)
            {
                base.Learn(x);
            }

            // Initial variables
            int[]      labels       = new int[rows];
            double[]   count        = new double[k];
            double[][] centroids    = Clusters.Centroids;
            double[][] newCentroids = Jagged.Zeros(k, cols);

            Iterations = 0;

            bool shouldStop = false;

            // We will solve the problem of assigning N data points
            // to K clusters where the cost will be their distance.
            this.munkres = new Munkres(x.Length, x.Length)
            {
                Tolerance = Tolerance
            };

            while (!shouldStop) // Main loop
            {
                Array.Clear(count, 0, count.Length);
                for (int i = 0; i < newCentroids.Length; i++)
                {
                    Array.Clear(newCentroids[i], 0, newCentroids[i].Length);
                }

                // Set the cost matrix for Munkres algorithm
                GetDistances(Distance, x, centroids, k, munkres.CostMatrix);

                munkres.Minimize(); // solve the assignment problem

                // Get the clustering from the assignment
                GetLabels(x, k, munkres.Solution, labels);

                // For each point in the data set,
                for (int i = 0; i < x.Length; i++)
                {
                    // Get the point
                    double[] point  = x[i];
                    double   weight = weights[i];

                    // Get the nearest cluster centroid
                    int c = labels[i];

                    if (c >= 0)
                    {
                        // Get the closest cluster centroid
                        double[] centroid = newCentroids[c];

                        // Increase the cluster's sample counter
                        count[c] += weight;

                        // Accumulate in the cluster centroid
                        for (int j = 0; j < point.Length; j++)
                        {
                            centroid[j] += point[j] * weight;
                        }
                    }
                }

                // Next we will compute each cluster's new centroid
                //  by dividing the accumulated sums by the number of
                //  samples in each cluster, thus averaging its members.
                Parallel.For(0, newCentroids.Length, ParallelOptions, i =>
                {
                    double sum = count[i];

                    if (sum > 0)
                    {
                        for (int j = 0; j < newCentroids[i].Length; j++)
                        {
                            newCentroids[i][j] /= sum;
                        }
                    }
                });

                // The algorithm stops when there is no further change in the
                //  centroids (relative difference is less than the threshold).
                shouldStop = converged(centroids, newCentroids);

                // go to next generation
                for (int i = 0; i < centroids.Length; i++)
                {
                    for (int j = 0; j < centroids[i].Length; j++)
                    {
                        centroids[i][j] = newCentroids[i][j];
                    }
                }
            }

            for (int i = 0; i < Clusters.Centroids.Length; i++)
            {
                // Compute the proportion of samples in the cluster
                Clusters.Proportions[i] = count[i] / weightSum;
            }

            this.Labels = labels;

            ComputeInformation(x, labels);

            return(Clusters);
        }