public void ConstructorFromPoint() { var M = new BooleanMatrix(new IntPoint(4, 5)); Assert.AreEqual(4, M.Width); Assert.AreEqual(5, M.Height); }
/// <summary> /// Finds all vectors v for which vM = 0, where M is an argument matrix. /// If rank of matrix is less then minimalRank exception is raised to protect from too big kernel. /// </summary> /// <param name="matrix">linear transformation</param> /// <param name="minimalRank">required minimal rank</param> /// <returns></returns> public static List <BooleanVector> GetKernel(BooleanMatrix matrix, int minimalRank) { matrix = new BooleanMatrix(matrix); var columnPivot = new List <int?>(); var row = 0; for (var column = 0; column < matrix.Width; column++) { var foundPivot = FindPivotAndSwapRows(matrix, row, column); if (foundPivot) { ReduceRows(matrix, row, column); columnPivot.Add(row); row++; } else { columnPivot.Add(null); } } if (row < minimalRank) { throw new InvalidOperationException("Matrix doesn't have sufficient rank"); } return(FindSolution(matrix, columnPivot, 0).Select(list => new BooleanVector(Enumerable.Reverse(list))).ToList()); }
public void Merge() { Assert.AreEqual(true, M[3, 2]); var o = new BooleanMatrix(4, 5); for (int x = 0; x < M.Width; ++x) { for (int y = 0; y < M.Height; ++y) { o[x, y] = x < 2 && y < 3; } } M.Merge(o); Assert.AreEqual(true, M[0, 0]); Assert.AreEqual(true, M[1, 2]); Assert.AreEqual(false, M[1, 3]); Assert.AreEqual(true, M[3, 2]); for (int x = 0; x < M.Width; ++x) { for (int y = 0; y < M.Height; ++y) { Assert.AreEqual((x + y) % 2 > 0 || x < 2 && y < 3, M[x, y]); } } }
public void Test(Instance instance) { var sim = new OracleCounterSimulator(); var len = instance.Kernel.Count; var saver = new List <IQArray <long> >(); for (int i = 0; i < len * 4; ++i) { var watch = System.Diagnostics.Stopwatch.StartNew(); var(vector, uf) = cs_helper.Run(sim, len, instance.ExtendedTransformation).Result; watch.Stop(); long ticks = watch.ElapsedTicks; Console.WriteLine("n: " + len + " RunTime: " + ticks); Assert.Equal(1, sim.GetOperationCount(uf)); saver.Add(vector); } var matrix = new BooleanMatrix(saver); var kernel = matrix.GetKernel(); Assert.Equal(instance.Kernel.Contains(true) ? 2 : 1, kernel.Count); Assert.Contains(instance.Kernel, kernel); }
/// <summary> /// Extend partial solution to column with given index. /// </summary> /// <param name="solutionVector">partial solution to be extended</param> /// <param name="upperTriangleMatrix">matrix in upper triangle form to be processed</param> /// <param name="column">index of column to be extended</param> /// <param name="row">index of row containing pivot for column, null if there is no pivot</param> /// <returns></returns> private static IEnumerable <List <bool> > ExtendSolutionVector( IReadOnlyList <bool> solutionVector, BooleanMatrix upperTriangleMatrix, int column, int?row) { if (row.HasValue) { var sum = false; for (var i = 1; column + i < upperTriangleMatrix.Width; i++) { sum ^= upperTriangleMatrix[row.Value][upperTriangleMatrix.Width.Value - i] & solutionVector[i - 1]; } return(new List <List <bool> > { new List <bool>(solutionVector) { sum } }); } return(new List <List <bool> > { new List <bool>(solutionVector) { true }, new List <bool>(solutionVector) { false } }); }
/// <summary> /// Swaps two rows of matrix. /// </summary> /// <param name="matrix">matrix to be processed</param> /// <param name="firstRow">index of first row</param> /// <param name="secondRow">index of second row</param> private static void SwapRows(BooleanMatrix matrix, int firstRow, int secondRow) { var row1 = matrix[firstRow]; var row2 = matrix[secondRow]; matrix[secondRow] = row1; matrix[firstRow] = row2; }
public void ConstructorCloning() { var M = new BooleanMatrix(this.M); Assert.AreEqual(4, M.Width); Assert.AreEqual(5, M.Height); for (int x = 0; x < M.Width; ++x) for (int y = 0; y < M.Height; ++y) Assert.AreEqual(this.M[x, y], M[x, y]); }
/// <summary> /// Reduce rows with index greater then <paramref name="row"/> to ensure that value in <paramref name="column"/> is equal /// to zero. /// </summary> /// <param name="matrix">processed matrix</param> /// <param name="row">index of first row</param> /// <param name="column">index of column to be cleared</param> private static void ReduceRows(BooleanMatrix matrix, int row, int column) { for (var i = row + 1; i < matrix.Height; i++) { if (matrix[i][column]) { matrix[i] -= matrix[row]; } } }
public void Test(Instance instance) { { var sim = new OracleCounterSimulator(); var len = instance.Kernel.Count; var saver = new List <IQArray <long> >(); for (int i = 0; i < len * 4; ++i) { var(vector, uf) = cs_helper.Run(sim, len, instance.ExtendedTransformation).Result; Assert.Equal(1, sim.GetOperationCount(uf)); saver.Add(vector); } var matrix = new BooleanMatrix(saver); var kernel = matrix.GetKernel(); Assert.Equal(instance.Kernel.Contains(true) ? 2 : 1, kernel.Count); Assert.Contains(instance.Kernel, kernel); } Stopwatch s = new Stopwatch(); s.Start(); for (int j = 0; j < 10; j++) { var sim = new OracleCounterSimulator(); var len = instance.Kernel.Count; var saver = new List <IQArray <long> >(); for (int i = 0; i < len * 4; ++i) { var(vector, uf) = cs_helper.Run(sim, len, instance.ExtendedTransformation).Result; Assert.Equal(1, sim.GetOperationCount(uf)); saver.Add(vector); } var matrix = new BooleanMatrix(saver); var kernel = matrix.GetKernel(); Assert.Equal(instance.Kernel.Contains(true) ? 2 : 1, kernel.Count); Assert.Contains(instance.Kernel, kernel); } s.Stop(); Console.Write(instance.instance); Console.Write(","); Console.Write(instance.kernel.Count()); Console.Write(","); Console.WriteLine(s.ElapsedMilliseconds); }
/// <summary> /// Finds first row (with index greater or equal to <paramref name="row"/>) for which value in <paramref name="column"/> is /// positive and swaps it with <paramref name="row"/>-th row. /// </summary> /// <param name="matrix">processed matrix</param> /// <param name="row">index of first row</param> /// <param name="column">index of column in which pivot is looked for</param> /// <returns></returns> private static bool FindPivotAndSwapRows(BooleanMatrix matrix, int row, int column) { for (var i = row; i < matrix.Height; i++) { if (!matrix[i][column]) { continue; } SwapRows(matrix, i, row); return(true); } return(false); }
/// <summary> /// Finds partial solutions for columns with index greater or equal to <paramref name="column"/>. /// </summary> /// <param name="upperTriangleMatrix">matrix in upper triangle form to be processed</param> /// <param name="columnPivot">indexes of rows containing pivots for every column</param> /// <param name="column">index of first column in partial solution</param> /// <returns></returns> private static IEnumerable <List <bool> > FindSolution(BooleanMatrix upperTriangleMatrix, IReadOnlyList <int?> columnPivot, int column) { if (column >= upperTriangleMatrix.Width) { return(new List <List <bool> > { new List <bool>() }); } return(FindSolution(upperTriangleMatrix, columnPivot, column + 1) .SelectMany(solutionVector => ExtendSolutionVector(solutionVector, upperTriangleMatrix, column, columnPivot[column])) .ToList()); }
public void Test(Instance instance) { var sim = new OracleCounterSimulator(); var len = instance.Kernel.Count; var saver = new List <IQArray <long> >(); for (int i = 0; i < len * 4; ++i) { var(vector, uf) = cs_helper.Run(sim, len, instance.ExtendedTransformation).Result; Assert.Equal(1, sim.GetOperationCount(uf)); saver.Add(vector); } var matrix = new BooleanMatrix(saver); var kernel = matrix.GetKernel(); Assert.Equal(instance.Kernel.Contains(true) ? 2 : 1, kernel.Count); Assert.Contains(instance.Kernel, kernel); }
/// <summary> /// Evaluates the function on a matrix argument. /// </summary> /// <param name="Argument">Function argument.</param> /// <param name="Variables">Variables collection.</param> /// <returns>Function result.</returns> public virtual IElement EvaluateMatrix(BooleanMatrix Argument, Variables Variables) { return(this.EvaluateMatrix((IMatrix)Argument, Variables)); }
public void TestCudafyGaussJordan() { var random = new Random(); for (int k = 0; k < 10; k++) { var matrix = new BooleanMatrix( Enumerable.Range(0, 5).Select(i1 => Enumerable.Range(0, 10).Select(i => random.Next() % 2 == 0))); StackListQueue <int> list2; int rows = matrix.Count; int columns = matrix.Length; lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix( new ArrayOfArray <int>(matrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()).ToArray()) .ToTwoDimensional()); CudafyMatrix.ExecuteGaussJordan(); list2 = new StackListQueue <int>(CudafyMatrix.GetIndexes() .Select((first, row) => new KeyValuePair <int, int>(row, first)) .Where(pair => pair.Value >= 0) .Select(pair => pair.Value) .ToList()); Console.WriteLine(matrix); Console.WriteLine(); Console.WriteLine(string.Join(Environment.NewLine, Enumerable.Range(0, rows) .Select(row => string.Join("", Enumerable.Range(0, columns) .Select( column => CudafyMatrix.GetMatrix()[row, column].ToString()) .ToList())).ToList())); Console.WriteLine(); Console.WriteLine(string.Join(Environment.NewLine, CudafyMatrix.GetIndexes().Select(i => i.ToString()).ToList())); } for (int i = matrix.Count; i-- > 0;) { BooleanVector vector = matrix.Dequeue(); if (BooleanVector.IsZero(vector)) { continue; } matrix.Enqueue(vector); } for (int i = matrix.Count; i-- > 0;) { BooleanVector vector = matrix.Dequeue(); int index = vector.IndexOf(true); for (int j = matrix.Count; j-- > 0;) { BooleanVector vector1 = matrix.Dequeue(); if (vector1.Count > index && vector1[index]) { vector1 = BooleanVector.Xor(vector1, vector); } if (BooleanVector.IsZero(vector1)) { continue; } matrix.Enqueue(vector1); } matrix.Enqueue(vector); } Console.WriteLine("matrix:"); Console.WriteLine(matrix); var list1 = new StackListQueue <int>(matrix.Select(booleanVector => booleanVector.IndexOf(true))); list1.Sort(); list2.Sort(); Console.WriteLine("list1:" + list1); Console.WriteLine("list2:" + list2); Assert.IsTrue(list1.SequenceEqual(list2)); } }
public void TestCudafyMacLane() { var random = new Random(); for (int k = 0; k < 10; k++) { var matrix = new BooleanMatrix( Enumerable.Range(0, 5).Select(i1 => Enumerable.Range(0, 10).Select(i => random.Next() % 2 == 0))); int[] indexes = Enumerable.Range(1, 5).Select(i => random.Next() % 5).ToArray(); Console.WriteLine(string.Join(",", indexes.Select(i => i.ToString()).ToList())); /////////////////////////////////////////////////// // Вычисление целевой функции обычным методом IEnumerable <KeyValuePair <int, int> > dictionary = indexes.Select((item, value) => new KeyValuePair <int, int>(value, item)); var matrix2 = new BooleanMatrix( dictionary.Select( pair1 => dictionary .Where(pair2 => pair2.Value == pair1.Key && pair2.Key != pair1.Key) .Select(pair => matrix[pair.Key]) .Aggregate(matrix[pair1.Key], BooleanVector.Xor))); int macLane1 = matrix2.MacLane; int rows = matrix.Count; int columns = matrix.Length; lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix( new ArrayOfArray <int>(matrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()).ToArray()) .ToTwoDimensional()); CudafyMatrix.SetIndexes(indexes.ToArray()); CudafyMatrix.ExecuteMacLane(); int macLane2 = CudafyMatrix.GetMacLane(); CudafyMatrix.ExecuteUpdate(); Console.WriteLine(string.Join(",", CudafyMatrix.GetIndexes().Select(i => i.ToString()).ToList())); Console.WriteLine(); Console.WriteLine(matrix); Console.WriteLine(); Console.WriteLine(matrix2); Console.WriteLine(); Console.WriteLine(string.Join(Environment.NewLine, Enumerable.Range(0, rows) .Select(row => string.Join("", Enumerable.Range(0, columns) .Select( column => CudafyMatrix.GetMatrix()[row, column].ToString()) .ToList())).ToList())); Console.WriteLine(); //Console.WriteLine(string.Join(Environment.NewLine, // Enumerable.Range(0, rows) // .Select(row => string.Join("", Enumerable.Range(0, columns) // .Select(column => CudafyMatrix.GetMatrix()[row * columns + column].ToString()).ToList())).ToList())); Console.WriteLine(macLane1); Console.WriteLine(macLane2); Assert.AreEqual(macLane1, macLane2); } } }
public bool IsPlanar(Graph graphArgument) { if (WorkerLog != null) { WorkerLog("Начало алгоритма Мак-Лейна"); } var graph = new Graph(graphArgument); Debug.Assert( graph.Children.All(pair => pair.Value .All(value => graph.Children.ContainsKey(value) && graph.Children[value].Contains(pair.Key)))); if (WorkerBegin != null) { WorkerBegin(); } // Шаг первый - удаляем все листья и узлы степени 2 if (WorkerLog != null) { WorkerLog("Удаляем все листья и узлы степени 2"); } // листья представляют собой дерево и нарисовать его плоскую укладку тривиально. graph.RemoveAllTrees(); // Замечание. Если на ребра планарного графа нанести произвольное число вершин степени 2, // то он останется планарным; равным образом, если на ребра непланарного графа // нанести вершины степени 2, то он планарным не станет. graph.RemoveIntermedians(); // Шаг второй - граф нужно укладывать отдельно по компонентам связности. var stackListQueue = new StackListQueue <Graph> { graph.GetAllSubGraphs() }; if (WorkerLog != null) { WorkerLog("Находим ВСЕ пути в графе длины не более размера графа + 1"); } // Глобальные кэшированные данные Dictionary <int, PathDictionary> cachedAllGraphPaths = graph.GetAllGraphPaths(); foreach (Graph subGraph in stackListQueue) { if (WorkerLog != null) { WorkerLog("Проверка связанной компоненты " + subGraph); } // листья представляют собой дерево и нарисовать его плоскую укладку тривиально. subGraph.RemoveAllTrees(); if (subGraph.Vertices.Count() < 2) { continue; } Dictionary <int, PathDictionary> cachedSubGraphPaths = Graph.GetSubgraphPaths(subGraph.Vertices, cachedAllGraphPaths); if (WorkerLog != null) { WorkerLog("Находим ВСЕ циклы в графе длины не менее 2 и не более размера графа"); } var circles = new StackListQueue <Circle>(cachedSubGraphPaths.Where(pair => pair.Key > 2) .SelectMany(pair => subGraph.Vertices .SelectMany(vertex => pair.Value.Where(pair2 => pair2.Key.Key.Equals(pair2.Key.Value)) .SelectMany( pair2 => pair2.Value.Select(path => new Circle(path.GetRange(0, path.Count - 1))))))); if (WorkerLog != null) { WorkerLog(string.Format("Количество циклов {0}", circles.Count())); } //if (WorkerLog != null) WorkerLog("Находим все циклы в графе"); //IEnumerable<Circle> circles = subGraph.GetAllGraphCircles(cachedSubGraphPaths); if (!circles.Any()) { continue; // граф — дерево и нарисовать его плоскую укладку тривиально. } if (WorkerLog != null) { WorkerLog("Удаляем дубликаты"); } circles = new StackListQueue <Circle>(circles.Distinct(CircleComparer)); if (WorkerLog != null) { WorkerLog(string.Format("Количество циклов {0}", circles.Count())); } //Debug.Assert(subGraph.Vertices.Count() == // circles.SelectMany(circle => circle.ToList()).Distinct().Count()); // С технической точки зрения проверять, что цикл является простым и тау-циклом нет необходимости, поскольку не // приведён алгорим позволяющий проверить , что цикл является тау-циклом за количество операций меньшее чем приведение // матрицы к каноническому виду. Поэтому если действительно надо сделать хорошую реализацию, то либо надо закоментировать // проверки циклов на простоту и что они являются тау-циклами с помощью приведения к каноническому виду , либо // предложить алгоритм быстрой проверки, что цикл является тау-циклом if (WorkerLog != null) { WorkerLog("Ограничиваем простыми циклами"); } circles.RemoveAll(Circle.IsNotSimple); if (WorkerLog != null) { WorkerLog(string.Format("Количество циклов {0}", circles.Count())); } if (WorkerLog != null) { WorkerLog("Удаляем элементарные циклы и петли"); } circles.RemoveAll(circle => circle.Count < 3); if (WorkerLog != null) { WorkerLog(string.Format("Количество циклов {0}", circles.Count())); } //if (WorkerLog != null) WorkerLog("Ограничиваем тау-циклами"); //circles.RemoveAll(circle => !circle.IsTau()); //if (WorkerLog != null) WorkerLog(string.Format("Количество циклов {0}", circles.Count())); Debug.WriteLine(string.Join(Environment.NewLine, circles.Select(circle => circle.ToString()))); if (WorkerLog != null) { WorkerLog("Строим матрицу над GF2 из найденных циклов"); } var booleanMatrix = new BooleanMatrix(circles.Select(subGraph.GetVector)); if (WorkerLog != null) { WorkerLog(string.Format("Размер матрицы {0}х{1}", booleanMatrix.Count(), booleanMatrix.Length)); } foreach (var r in booleanMatrix) { if (r.Count() < booleanMatrix.Length) { r.Add(Enumerable.Repeat(false, booleanMatrix.Length - r.Count())); } } Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); // отыскание минимума некоторого функционала на множестве базисов подпространства квазициклов // Шаг 1. Приведение матрицы к каноническому виду if (WorkerLog != null) { WorkerLog("Приводим матрицу к каноническому виду"); } if (Settings.EnableCudafy) { lock (CudafyMatrix.Semaphore) { try { ///////////////////////////////////////////////////// // Использование параллельных вычислений CUDA // для приведения матрицы к каноническому виду CudafyMatrix.SetMatrix( new ArrayOfArray <int>( booleanMatrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()).ToArray()) .ToTwoDimensional()); // Использование алгоритма Гаусса-Жордана // Для приведения матрицы к каноническому виду CudafyMatrix.ExecuteGaussJordan(); // Удаляем нулевые строки int[][] arrayOfArray = new TwoDimensionalArray <int>(CudafyMatrix.GetMatrix()).ToArrayOfArray(); booleanMatrix = new BooleanMatrix(CudafyMatrix.GetIndexes() .Select((first, row) => new KeyValuePair <int, int>(row, first)) .Where(pair => pair.Value >= 0) .Select(pair => arrayOfArray[pair.Key].Select(value => value != 0))); CudafyMatrix.SetMatrix( new ArrayOfArray <int>( booleanMatrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()).ToArray()) .ToTwoDimensional()); } catch (Exception ex) { if (WorkerLog != null) { WorkerLog(ex.ToString()); } ///////////////////////////////////////////////////// // Приведение матрицы к каноническому виду обычным способом booleanMatrix.GaussJordan(); booleanMatrix.RemoveAll(BooleanVector.IsZero); } if (WorkerLog != null) { WorkerLog(string.Format("Размер матрицы {0}х{1}", booleanMatrix.Count(), booleanMatrix.Length)); } // Матрица имеет канонический вид Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); Debug.Assert(booleanMatrix.Select(vector => vector.IndexOf(true)).Distinct().Count() == booleanMatrix.Count); Debug.Assert(booleanMatrix.Select(vector => vector.IndexOf(true)) .SelectMany( index => booleanMatrix.Where(vector => vector.Count > index && vector[index])) .Count() == booleanMatrix.Count); // Поскольку в колонках содержится по одной единице, то к строке можно прибавить только одну другую строку int n = booleanMatrix.Count; int macLane; try { ///////////////////////////////////////////////////// // Использование параллельных вычислений CUDA // для расчёта целевой функции симплекс-метода Debug.Assert(CudafyMatrix.GetMatrix() != null); CudafyMatrix.SetIndexes(Enumerable.Range(0, n).ToArray()); CudafyMatrix.ExecuteMacLane(); macLane = CudafyMatrix.GetMacLane(); #if DEBUG int[][] arrayOfArray = new TwoDimensionalArray <int>(CudafyMatrix.GetMatrix()).ToArrayOfArray(); Debug.WriteLine(string.Join(Environment.NewLine, arrayOfArray.Select(v => string.Join(",", v.Select(i => i.ToString()))))); #endif } catch (Exception ex) { if (WorkerLog != null) { WorkerLog(ex.ToString()); } /////////////////////////////////////////////////// // Вычисление целевой функции обычным методом macLane = booleanMatrix.MacLane; } Debug.WriteLine("macLane = " + macLane); Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); int k = Math.Min(2, Math.Max(1, n)); k = Math.Min(n, k); if (WorkerLog != null) { WorkerLog("Начало симплекс-метода"); } if (WorkerLog != null) { WorkerLog("Текущий macLane = " + macLane); } for (bool updated = true; k <= n && updated && macLane > 0;) { Debug.Assert(booleanMatrix.Length == subGraph.Count()); List <int> values = Enumerable.Range(0, n).ToList(); updated = false; List <int> indexOfIndex = Enumerable.Range(n - k, k).ToList(); while (macLane > 0) { if (WorkerLog != null) { WorkerLog(string.Format("Перебираем индексы в позициях {0}", string.Join(",", indexOfIndex.Select(index => index.ToString(CultureInfo.InvariantCulture))))); } CudafyMatrix.SetMatrix( new ArrayOfArray <int>( booleanMatrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()) .ToArray()) .ToTwoDimensional()); List <int> indexes = values.ToList(); foreach (int index in indexOfIndex) { indexes[index] = n - 1; } while (macLane > 0) { Debug.Write(string.Format("Проверяем индексы {0} ... ", string.Join(",", indexes.Select(index => index.ToString(CultureInfo.InvariantCulture))))); // Проверяем, что матрица образованная indexes является обратимой var detMatrix = new BooleanMatrix(indexes); if (detMatrix.Det()) { BooleanMatrix matrix2; int macLane2 = 0; try { ///////////////////////////////////////////////////// // Использование параллельных вычислений CUDA // для расчёта целевой функции симплекс-метода Debug.Assert(CudafyMatrix.GetMatrix() != null); CudafyMatrix.SetIndexes(indexes.ToArray()); CudafyMatrix.ExecuteMacLane(); macLane2 = CudafyMatrix.GetMacLane(); #if DEBUG CudafyMatrix.ExecuteUpdate(); int[][] arrayOfArray = new TwoDimensionalArray <int>(CudafyMatrix.GetMatrix()).ToArrayOfArray(); matrix2 = new BooleanMatrix( arrayOfArray.Select(r => new BooleanVector(r.Select(c => c != 0)))); CudafyMatrix.SetMatrix( new ArrayOfArray <int>( booleanMatrix.Select(v => v.Select(b => b ? 1 : 0).ToArray()) .ToArray()) .ToTwoDimensional()); #endif } catch (Exception ex) { if (WorkerLog != null) { WorkerLog(ex.ToString()); } /////////////////////////////////////////////////// // Вычисление целевой функции обычным методом Dictionary <int, int> dictionary = indexes.Select((item, value) => new KeyValuePair <int, int>(value, item)) .ToDictionary(pair => pair.Key, pair => pair.Value); matrix2 = new BooleanMatrix( dictionary.Select( pair1 => dictionary .Where( pair2 => pair2.Value == pair1.Key && pair2.Key != pair1.Key) .Select(pair => booleanMatrix[pair.Key]) .Aggregate(booleanMatrix[pair1.Key], BooleanVector.Xor))); macLane2 = matrix2.MacLane; } finally { Debug.WriteLine("macLane = " + macLane2); } if (macLane > macLane2) { if (WorkerLog != null) { WorkerLog("Найденое решение улучшилось ( " + macLane + " -> " + macLane2 + " )"); } Debug.WriteLine("macLane: " + macLane + "->" + macLane2); values = indexes.ToList(); macLane = macLane2; updated = true; Debug.WriteLine(string.Join(",", values.Select(item => item.ToString()))); Debug.WriteLine("matrix2:"); Debug.WriteLine(matrix2); } if (macLane == 0) { break; } } else { Debug.WriteLine("Матрица не обратима"); } int i = k; while (i-- > 0) { if (indexes[indexOfIndex[i]]-- > 0) { break; } else { indexes[indexOfIndex[i]] = n - 1; } } if (i < 0) { break; } } int count = k; while (count-- > 0) { if (indexOfIndex[count]-- > (count == 0 ? 0 : (indexOfIndex[count - 1] + 1))) { break; } else { indexOfIndex[count] = (count == (k - 1) ? n - 1 : (indexOfIndex[count + 1] - 1)); } } if (count < 0) { break; } } if (WorkerLog != null) { WorkerLog("Смена начальной точки симплекс-метода"); } try { ///////////////////////////////////////////////////// // Использование параллельных вычислений CUDA // для смены базиса симплекс-метода Debug.Assert(CudafyMatrix.GetMatrix() != null); CudafyMatrix.SetIndexes(values.ToArray()); CudafyMatrix.ExecuteUpdate(); #if DEBUG int[][] arrayOfArray = new TwoDimensionalArray <int>(CudafyMatrix.GetMatrix()).ToArrayOfArray(); booleanMatrix = new BooleanMatrix(arrayOfArray.Select(r => new BooleanVector(r.Select(c => c != 0)))); #endif } catch (Exception ex) { if (WorkerLog != null) { WorkerLog(ex.ToString()); } /////////////////////////////////////////////////// // Cмена базиса симплекс-метода обычным методом Dictionary <int, int> dictionary = values.Select((item, value) => new KeyValuePair <int, int>(value, item)) .ToDictionary(pair => pair.Key, pair => pair.Value); booleanMatrix = new BooleanMatrix( dictionary.Select( pair1 => dictionary .Where(pair2 => pair2.Value == pair1.Key && pair2.Key != pair1.Key) .Select(pair => booleanMatrix[pair.Key]) .Aggregate(booleanMatrix[pair1.Key], BooleanVector.Xor))); } Debug.WriteLine(string.Join(",", values.Select(item => item.ToString()))); Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); } if (macLane > 0) { if (WorkerLog != null) { WorkerLog("Не найдено нулевое значение фунции Мак-Лейна"); } if (WorkerLog != null) { WorkerLog("Граф не планарен"); } bool result = false; if (WorkerComplite != null) { WorkerComplite(result); } return(result); } } } else { // Приведение матрицы к каноническому виду обычным способом booleanMatrix.GaussJordan(); booleanMatrix.RemoveAll(BooleanVector.IsZero); if (WorkerLog != null) { WorkerLog(string.Format("Размер матрицы {0}х{1}", booleanMatrix.Count(), booleanMatrix.Length)); } int macLane = booleanMatrix.MacLane; Debug.WriteLine("macLane = " + macLane); Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); int n = booleanMatrix.Count; int k = Math.Min(2, Math.Max(1, n)); k = Math.Min(n, k); if (WorkerLog != null) { WorkerLog("Начало симплекс-метода"); } if (WorkerLog != null) { WorkerLog("Текущий macLane = " + macLane); } for (bool updated = true; k <= n && updated && macLane > 0;) { Debug.Assert(booleanMatrix.Length == subGraph.Count()); List <int> values = Enumerable.Range(0, n).ToList(); updated = false; List <int> indexOfIndex = Enumerable.Range(n - k, k).ToList(); while (macLane > 0) { if (WorkerLog != null) { WorkerLog(string.Format("Перебираем индексы в позициях {0}", string.Join(",", indexOfIndex.Select(index => index.ToString(CultureInfo.InvariantCulture))))); } CudafyMatrix.SetMatrix( new ArrayOfArray <int>( booleanMatrix.Select(vector => vector.Select(b => b ? 1 : 0).ToArray()) .ToArray()) .ToTwoDimensional()); List <int> indexes = values.ToList(); foreach (int index in indexOfIndex) { indexes[index] = n - 1; } while (macLane > 0) { Debug.Write(string.Format("Проверяем индексы {0} ... ", string.Join(",", indexes.Select(index => index.ToString(CultureInfo.InvariantCulture))))); // Проверяем, что матрица образованная indexes является обратимой var detMatrix = new BooleanMatrix(indexes); if (detMatrix.Det()) { int macLane2 = 0; /////////////////////////////////////////////////// // Вычисление целевой функции обычным методом Dictionary <int, int> dictionary = indexes.Select((item, value) => new KeyValuePair <int, int>(value, item)) .ToDictionary(pair => pair.Key, pair => pair.Value); var matrix2 = new BooleanMatrix( dictionary.Select( pair1 => dictionary .Where( pair2 => pair2.Value == pair1.Key && pair2.Key != pair1.Key) .Select(pair => booleanMatrix[pair.Key]) .Aggregate(booleanMatrix[pair1.Key], BooleanVector.Xor))); macLane2 = matrix2.MacLane; Debug.WriteLine("macLane = " + macLane2); if (macLane > macLane2) { if (WorkerLog != null) { WorkerLog("Найденое решение улучшилось ( " + macLane + " -> " + macLane2 + " )"); } Debug.WriteLine("macLane: " + macLane + "->" + macLane2); values = indexes.ToList(); macLane = macLane2; updated = true; Debug.WriteLine(string.Join(",", values.Select(item => item.ToString()))); Debug.WriteLine("matrix2:"); Debug.WriteLine(matrix2); } if (macLane == 0) { break; } } else { Debug.WriteLine("Матрица не обратима"); } int i = k; while (i-- > 0) { if (indexes[indexOfIndex[i]]-- > 0) { break; } else { indexes[indexOfIndex[i]] = n - 1; } } if (i < 0) { break; } } int count = k; while (count-- > 0) { if (indexOfIndex[count]-- > (count == 0 ? 0 : (indexOfIndex[count - 1] + 1))) { break; } else { indexOfIndex[count] = (count == (k - 1) ? n - 1 : (indexOfIndex[count + 1] - 1)); } } if (count < 0) { break; } } if (WorkerLog != null) { WorkerLog("Смена начальной точки симплекс-метода"); } /////////////////////////////////////////////////// // Cмена базиса симплекс-метода обычным методом Dictionary <int, int> dictionary2 = values.Select((item, value) => new KeyValuePair <int, int>(value, item)) .ToDictionary(pair => pair.Key, pair => pair.Value); booleanMatrix = new BooleanMatrix( dictionary2.Select( pair1 => dictionary2 .Where(pair2 => pair2.Value == pair1.Key && pair2.Key != pair1.Key) .Select(pair => booleanMatrix[pair.Key]) .Aggregate(booleanMatrix[pair1.Key], BooleanVector.Xor))); Debug.WriteLine(string.Join(",", values.Select(item => item.ToString()))); Debug.WriteLine("matrix:"); Debug.WriteLine(booleanMatrix); } if (macLane > 0) { if (WorkerLog != null) { WorkerLog("Не найдено нулевое значение фунции Мак-Лейна"); } if (WorkerLog != null) { WorkerLog("Граф не планарен"); } bool result = false; if (WorkerComplite != null) { WorkerComplite(result); } return(result); } } if (WorkerLog != null) { WorkerLog("Конец проверки связанной компоненты"); } } { if (WorkerLog != null) { WorkerLog("Конец алгоритма Мак-Лейна"); } if (WorkerLog != null) { WorkerLog("Граф планарен"); } bool result = true; if (WorkerComplite != null) { WorkerComplite(result); } return(result); } }