private static void Main(string[] args) { // Параметры программы string inputFileName = "input.csv"; string outputFileName = "output.csv"; double unit = 1.0; double epsilon = 0.0000000001; var nodeList = new StackListQueue <string>(); var matrix = new DoubleMatrix(); // Определение параметров программы for (int i = 0; i < args.Length; i++) { if (string.CompareOrdinal(args[i], "-s") == 0 || string.CompareOrdinal(args[i], "-i") == 0) { inputFileName = args[++i]; } else if (string.CompareOrdinal(args[i], "-d") == 0 || string.CompareOrdinal(args[i], "-o") == 0) { outputFileName = args[++i]; } else if (string.CompareOrdinal(args[i], "-b1") == 0) { unit = 1.0; } else if (string.CompareOrdinal(args[i], "-b100") == 0) { unit = 100.0; } else if (string.CompareOrdinal(args[i], "-e") == 0) { epsilon = Math.Pow(0.1, Int32.ParseAsString(args[++i])); } } // Загрузка матрицы из файла int lines = 0; using (StreamReader reader = File.OpenText(inputFileName)) { // регулярное выражение для разбора полей исходного файла var regex = new Regex(@"\s*(?<from>[^;]+)\s*;\s*(?<to>[^;]+)\s*;\s*(?<value>\d+([,.]\d*)?)\s*"); for (string line = reader.ReadLine();; line = reader.ReadLine()) { lines++; Match match = regex.Match(line); int i = nodeList.IndexOf(match.Groups["from"].Value); if (i == -1) { i = nodeList.Count; if (!nodeList.Any()) { matrix.Add(new DoubleVector { 0.0 }); } else { matrix.AddColumn(); matrix.AddRow(); } nodeList.Add(match.Groups["from"].Value); Debug.WriteLine("Зарегистрирован участник {0} под номером {1}", nodeList.Last(), i); Debug.WriteLine("Текущий размер матрицы {0}x{1}", matrix.Rows, matrix.Columns); } int j = nodeList.IndexOf(match.Groups["to"].Value); if (j == -1) { j = nodeList.Count; matrix.AddColumn(); matrix.AddRow(); nodeList.Add(match.Groups["to"].Value); Debug.WriteLine("Зарегистрирован участник {0} под номером {1}", nodeList.Last(), j); Debug.WriteLine("Текущий размер матрицы {0}x{1}", matrix.Rows, matrix.Columns); } double value = Double.ParseAsString(match.Groups["value"].Value); matrix[i][j] = value / unit; if (reader.EndOfStream) { break; } } reader.Close(); } Console.WriteLine("Прочитано строк = {0}", lines); // Проверка исходных данных Debug.Assert(matrix.Rows == matrix.Columns); Debug.Assert(matrix.All(row => row.All(x => x >= 0.0 - epsilon && x <= 1.0 + epsilon))); int total = Math.Max(matrix.Rows, matrix.Columns); #if DEBUG // Проверка исходных данных for (int i = 0; i < total; i++) { double s = 0.0; for (int j = 0; j < total; j++) { s += matrix[j][i]; } Debug.Assert(s <= 1.0 + epsilon); } #endif // Определение компонент связанности var groupList = new StackListQueue <StackListQueue <int> >(); // Инициализация определения компонент связанности for (int i = 0; i < total; i++) { groupList.Add(new StackListQueue <int> { i }); } for (int i = groupList.Count - 1; i > 0; i--) { for (int j = i - 1; j >= 0; j--) { // Проверяем существование путей из одной группы в другую группу if (DoubleMatrix.IsZero(matrix.SubMatrix(groupList[i], groupList[j])) && DoubleMatrix.IsZero(matrix.SubMatrix(groupList[j], groupList[i]))) { continue; } // Если существует путь между двумя группами // то объединяем группы в одну groupList[j].AddRange(groupList[i]); groupList.RemoveAt(i); Debug.WriteLine("Группа {0} присоеденена к группе {1}", i, j); break; } } Console.WriteLine("Обнаружено {0} групп", groupList.Count); #if DEBUG for (int i = 0; i < groupList.Count; i++) { Debug.WriteLine("Группа #{0}", i); foreach (int j in groupList[i]) { Debug.WriteLine(nodeList[j]); } } #endif using (StreamWriter writer = File.CreateText(outputFileName)) { // Для каждой компоненты связанности foreach (var group in groupList) { int n = group.Count; // Отсекаются группы из одного участника if (n == 1) { continue; } Console.WriteLine("Анализируется группа из {0} участников", n); var e = new DoubleMatrix(n, n); for (int i = 0; i < n; i++) { e[i][i] = 1.0; } // Получение выборки из исходной матрицы E-A DoubleMatrix a = matrix.SubMatrix(group, group); DoubleMatrix b = e - a; #if DEBUG // Сохраняем матрицу для дальнейшей самопроверки var z = new DoubleMatrix(b.Select(row => new DoubleVector(row))); Debug.Assert(z.Rows == n); Debug.Assert(z.Columns == n); #endif // Дописывание к выборке единичной матрицы справа b.AppendColumns(e); Debug.Assert(b.Rows == n); Debug.Assert(b.Columns == 2 * n); // Приведение выборки к каноническому виду преобразованиями по строкам b.GaussJordan( DoubleMatrix.Search.SearchByRows, DoubleMatrix.Transform.TransformByRows, 0, n); Debug.Assert(b.All(row => !DoubleVector.IsZero(new DoubleVector(row.GetRange(0, n))))); // Сортировка строк для приведения канонической матрицы к единичной матрице var dic = new Dictionary <int, DoubleVector>(); for (int i = 0; i < n; i++) { int j = 0; DoubleVector vector = b[i]; while (DoubleVector.IsZero(vector[j])) { j++; } dic.Add(j, vector); } // Получение обратной матрицы для E-A var c = new DoubleMatrix(); for (int i = 0; i < n; i++) { c.Add(new DoubleVector(dic[i].GetRange(n, n))); } #if DEBUG // Проверяем, что полученная матрица действительно является обратной DoubleMatrix y = c * z; Debug.Assert(y.Rows == n); Debug.Assert(y.Columns == n); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { Debug.Assert(Math.Abs(y[i][j] - 1.0) < epsilon); } else { Debug.Assert(Math.Abs(y[i][j] - 0.0) < epsilon); } } } Console.WriteLine("Сверка вычислений произведена"); #endif Debug.Assert(c.Rows == c.Columns); // Проверка выходных данных #if DEBUG //for (int i = 0; i < n; i++) //{ // for (int j = 0; j < n; j++) // { // if (i == j) continue; // Debug.Assert(c[i][j] >= 0.0 - epsilon && c[i][j] <= 1.0 + epsilon); // } //} #endif // Выгрузка ненулевых элементов обратной матрицы в файл for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { continue; } if (DoubleMatrix.IsZero(c[i][j])) { continue; } // Сохранение полей в том же формате, что и исходные данные writer.Write(nodeList[group[i]]); writer.Write(";"); writer.Write(nodeList[group[j]]); writer.Write(";"); writer.Write(c[i][j].ToString().Replace(",", ".")); writer.WriteLine(); } } } } }