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]); }
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); }
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."); }
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]); }
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]); } }
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]); } }
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]); }
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 })); }
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]); }
/// <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); }