public BipartiteGraphMatching <T> GetAssignmentMatching() { if (Data.USize != Data.VSize || Properties.IsNegativeWeighted || !IsComplete()) { throw new InvalidOperationException(); } BipartiteGraphMatching <T> graph = Clone <BipartiteGraphMatching <T> >(false); Func <int, int, double, EdgeData, EdgeData> func1 = (row, column, minVal, x) => { var edgeData = x.WithWeight(x.Weight - minVal); if (MathUtils.AreEqual(edgeData.Weight, 0)) { graph.EnsureEdge(column, row, x.Weight); } return(edgeData); }; Func <int, int, double, EdgeData, EdgeData> func2 = (row, column, minVal, x) => { var edgeData = x.WithWeight(x.Weight + minVal); if (!MathUtils.AreEqual(edgeData.Weight, 0)) { graph.EnsureNoEdge(column, row); } return(edgeData); }; RectMatrix <EdgeData, Color> matrix = Data.Matrix.Clone(); int rowCount = matrix.Size.RowCount; for (int n = 0; n < rowCount; n++) { double minVal = matrix.GetRowItemList(n).Select(x => x.Weight).Min(); matrix.TranslateRow(n, func1, minVal); } if (graph.IsPerfect()) { return(graph); } int columnCount = matrix.Size.ColumnCount; for (int n = 0; n < columnCount; n++) { double minVal = matrix.GetColumnItemList(n).Select(x => x.Weight).Min(); matrix.TranslateColumn(n, func1, minVal); } if (graph.IsPerfect()) { return(graph); } while (true) { var matching = graph.GetMaximalMatchingCore(); if (matching.IsPerfect()) { return(CloneWithEdges(matching)); } Color color1 = Color.CreateColor(); matching.Data.GetVVertexList() .Where(x => x.Degree != 0) .ForEach(x => matrix.RowAttributes[x.Handle] = color1); Color color2 = Color.CreateColor(); matrix.TranslateRowAttributes((row, rowColor) => rowColor != color1, x => color2); matrix.ForEach((row, column, rowColor, columnColor, x) => rowColor == color2 && MathUtils.AreEqual(x.Weight, 0), (row, column, x) => { matrix.ColumnAttributes[column] = color2; for (int n = 0; n < matrix.Size.RowCount; n++) { if (matching.AreVerticesAdjacent(column, n)) { matrix.RowAttributes[n] = color2; } } }); Color color3 = Color.CreateColor(); matrix.TranslateColumnAttributes((column, columnColor) => columnColor == color2, x => color3); matrix.TranslateRowAttributes((row, rowColor) => rowColor != color2, x => color3); double minValue = matrix.GetItems((row, column, rowColor, columnColor, x) => rowColor != color3 && columnColor != color3).Select(x => x.Weight).Min(); matrix.Translate((row, column, rowColor, columnColor, x) => rowColor != color3 && columnColor != color3, func1, minValue); matrix.Translate((row, column, rowColor, columnColor, x) => rowColor == color3 && columnColor == color3, func2, minValue); } }
protected virtual void Assign(RectMatrix <T> clone) { clone.EnsureSize(Size.RowCount, Size.ColumnCount); Array.Copy(this.data, clone.data, this.data.Length); }