public new bool Contains(IEnumerable <T> collection) { if (Settings.EnableCudafy) { try { int[,] matrix; int first; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( collection.Select(GetInts).Select(item => item.ToArray()).ToArray(), this.Select(GetInts).Select(item => item.ToArray()).ToArray() ); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZeroFirstIndexOfNonPositive(); first = CudafyMatrix.GetFirst(); } return(first < 0); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); return(collection.All(Contains)); } } return(collection.All(Contains)); }
public IEnumerable <Path> SplitBy(Segment segment) { var list = new StackListQueue <Path>(); StackListQueue <int> indexes; try { int[,] matrix; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( segment.Select(GetInts).Select(item => item.ToArray()).ToArray(), GetRange(1, Count - 2).Select(GetInts).Select(item => item.ToArray()).ToArray() ); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = new StackListQueue <int>(CudafyMatrix.GetIndexes() .Where(index => index >= 0) .Select(index => index + 1)); } } catch (Exception ex) { Debug.WriteLine(ex.ToString()); indexes = new StackListQueue <int>(GetRange(1, Count - 2).Intersect(segment).Select(v => IndexOf(v))); } indexes.Sort(); indexes.Prepend(0); indexes.Append(Count - 1); for (int prev = indexes.Dequeue(); indexes.Any(); prev = indexes.Dequeue()) { if (((prev + 1) == indexes[0]) && segment.Contains(this[prev]) && segment.Contains(this[indexes[0]])) { continue; } list.Add(new Path(GetRange(prev, indexes[0] - prev + 1))); } Debug.WriteLineIf(list.Any(), this + " split by " + segment + " is " + string.Join(",", list.Select(item => item.ToString()))); return(list); }
public IEnumerable <T> Distinct() { if (Settings.EnableCudafy) { try { if (Count == 0) { return(new StackListQueue <T>()); } IEnumerable <IEnumerable <int> > list = this.Select(GetInts); int[,] matrix; int[] indexes; lock (CudafySequencies.Semaphore) { int[][] arr = this.Select(GetInts).Select(item => item.ToArray()).ToArray(); CudafySequencies.SetSequencies(arr, arr); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = CudafyMatrix.GetIndexes(); } return(indexes.Where((value, index) => value == index) .Select(index => this[index])); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); return(this.ToList().Distinct()); } } return(this.ToList().Distinct()); }
public bool IsPlanar(Graph graphArgument) { var enableCudafy = Settings.EnableCudafy; Settings.EnableCudafy = true; 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(); // Шаг второй - граф нужно укладывать отдельно по компонентам связности. if (WorkerLog != null) { WorkerLog("Находим ВСЕ пути в графе длины не более размера графа + 1"); } Dictionary <int, PathDictionary> cachedAllGraphPaths = graph.GetAllGraphPaths(); var queue = new StackListQueue <Context> { graph.GetAllSubGraphs().Select(subgraph => new Context { SubGraphQueue = new StackListQueue <Graph> { subgraph }, CachedSubGraphPathsQueue = new StackListQueue <Dictionary <int, PathDictionary> > { Graph.GetSubgraphPaths(subgraph.Vertices, cachedAllGraphPaths) }, }) }; Debug.WriteLine("start "); foreach (Context context in queue) { while (context.SubGraphQueue.Any()) { Graph subGraph = context.SubGraphQueue.Dequeue(); if (WorkerLog != null) { WorkerLog("Проверка связанной компоненты " + subGraph); } Dictionary <int, PathDictionary> cachedSubGraphPaths = context.CachedSubGraphPathsQueue.Dequeue(); // На вход подаются графы, обладающие следующими свойствами: // граф связный; // граф имеет хотя бы один цикл; // граф не имеет мостиков, т. е. ребер, после удаления которых // граф распадается на две компонеты связности. if (WorkerLog != null) { WorkerLog( "Находим мосты после удаления которых граф распадается на несколько компонет связности"); } var vertices = new StackListQueue <Vertex>(subGraph.Vertices); var bridges = new StackListQueue <Vertex>(); for (int i = 0; i < vertices.Count; i++) { Vertex dequeue = vertices.Dequeue(); IEnumerable <Graph> subsubgraphs = subGraph.GetSubgraph(vertices).GetAllSubGraphs(); if (subsubgraphs.Count() > 1) { bridges.Add(dequeue); } vertices.Enqueue(dequeue); } Debug.Assert(bridges.Count != vertices.Count); if (bridges.Any()) { // Если в графе есть мосты, то их нужно разрезать, провести отдельно плоскую укладку // каждой компоненты связности, а затем соединить их мостами. // Здесь может возникнуть трудность: в процессе укладки концевые вершины моста могут // оказаться внутри плоского графа. Нарисуем одну компоненту связности, // и будем присоединять к ней другие последовательно. // Каждую новую компоненту связности будем рисовать в той грани, в которой лежит // концевая вершина соответствующего моста. Так как граф связности мостами компонент // связности является деревом, мы сумеем получить плоскую укладку. if (WorkerLog != null) { WorkerLog( "В графе есть мосты, их нужно разрезать, провести отдельно плоскую укладку, а затем соединить их мостами."); } if (WorkerLog != null) { WorkerLog("Мосты: " + string.Join(",", bridges)); } IEnumerable <Vertex> exceptBridges = vertices.Except(bridges); IEnumerable <Graph> subsubgraphs = subGraph.GetSubgraph(exceptBridges).GetAllSubGraphs(); Debug.WriteLine("subsubgraphs = " + subsubgraphs.Count()); context.SubGraphQueue.Enqueue( subsubgraphs.Select(subgraph => subGraph.GetSubgraph(subgraph.Vertices.Union(bridges)))); context.CachedSubGraphPathsQueue.Enqueue( subsubgraphs.Select( subgraph => Graph.GetSubgraphPaths(subgraph.Vertices.Union(bridges), cachedSubGraphPaths))); continue; } if (WorkerLog != null) { WorkerLog("Находим ЛЮБОЙ МАКСИМАЛЬНОЙ ДЛИНЫ простой цикл в графе"); } Circle circle = null; for (int i = cachedSubGraphPaths.Keys.Max(); i > 3; i--) { foreach (var pair in cachedSubGraphPaths.Where(pair => pair.Key == i)) { foreach ( var key in subGraph.Vertices.Select(vertex => new KeyValuePair <Vertex, Vertex>(vertex, vertex)) ) { if (pair.Value.ContainsKey(key) && pair.Value[key].Any()) { foreach (Path path in pair.Value[key]) { circle = new Circle(path.GetRange(0, path.Count - 1)); if (Circle.IsSimple(circle)) { break; } circle = null; } if (circle != null) { break; } } if (circle != null) { break; } } if (circle != null) { break; } } if (circle != null) { break; } } if (circle == null && !context.Edges.Any()) { // граф — дерево и нарисовать его плоскую укладку тривиально. // Поскольку мы ещё не начинали рисовать, то значит всё проверено continue; } // Инициализация алгоритма производится так: выбираем любой простой цикл; // и получаем две грани: Γ1 — внешнюю и Γ2 — внутреннюю if (circle != null && !context.Edges.Any()) { context.Edges.Add(new Edge(circle)); } if (circle != null) { context.Edges.Add(new Edge(circle)); context.Builded.Add(context.Edges.Last()); } // Если циклов нет, то надо проверить, что данное дерево // можно вписать в уже построенный граф Debug.WriteLine("SubGraph " + subGraph); Debug.WriteLine("builded " + context.Builded); Debug.WriteLine("edges:" + string.Join(Environment.NewLine, context.Edges.Select(e => e.ToString()))); //// Каждый сегмент S относительно уже построенного графа G′ представляет собой одно из двух: //// ребро, оба конца которого принадлежат G′, но само оно не принадлежит G′; //// связную компоненту графа G – G′, дополненную всеми ребрами графа G, //// один из концов которых принадлежит связной компоненте, //// а второй из графа G′. VertexSortedCollection buildedVertices = context.Builded.Vertices; Dictionary <int, PathDictionary> fromTo = Graph.GetFromToPaths(buildedVertices, buildedVertices, cachedSubGraphPaths); var paths = new PathCollection(fromTo .SelectMany(pair => pair.Value) .SelectMany(pair => pair.Value) .Where(Path.IsNoVertix) .Where(Path.IsNoCircle) ); Debug.WriteLine("paths " + paths); //var secondGraph = new Graph(subGraph.Except(context.Builded)); //if (secondGraph.Any()) //{ // IEnumerable<Graph> collection = secondGraph.GetAllSubGraphs(); // context.SubGraphQueue.Enqueue(collection); // context.CachedSubGraphPathsQueue.Enqueue( // collection.Select(subgraph => Graph.GetSubgraphPaths(subgraph.Vertices, cachedSubGraphPaths))); //} paths.ReplaceAll(paths.Distinct()); Debug.WriteLine("paths " + paths); paths.RemoveAll(context.Builded.Contains); Debug.WriteLine("paths " + paths); Debug.WriteLine("builded " + context.Builded); Debug.WriteLine("edges:" + string.Join(Environment.NewLine, context.Edges.Select(e => e.ToString()))); while (paths.Any()) { paths.RemoveAll(context.Builded.Contains); Debug.WriteLine("paths " + paths); if (!paths.Any()) { continue; } if (Settings.EnableCudafy) { try { while (paths.Any(Path.IsLong)) { // Находим для всех путей их перечечения с уже построенным графом // Разбиваем пути в найденных точках пересечения с уже построенным графом // Если точек пересечения не найдено, то выходим из цикла int[,] matrix; int[] indexes; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( paths.Select( path => path.GetRange(1, path.Count - 2) .Select(vertex => vertex.Id) .ToArray()) .ToArray(), context.Builded.Vertices.Select( vertex => new StackListQueue <int>(vertex.Id).ToArray()) .ToArray() ); CudafySequencies.Execute("CountIntersections"); // подсчитываем число пересечений matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfNonZero(); // находим индексы ненулевых элементов в строках indexes = CudafyMatrix.GetIndexes(); } Dictionary <int, int> dictionary = indexes.Select( (value, index) => new KeyValuePair <int, int>(index, value)) .Where(pair => pair.Value >= 0) .ToDictionary(pair => pair.Key, pair => pair.Value); if (!dictionary.Any()) { break; } Debug.Assert(dictionary.All(pair => pair.Key >= 0)); Debug.Assert(dictionary.All(pair => pair.Value >= 0)); Debug.Assert(dictionary.All(pair => pair.Key < paths.Count)); Debug.Assert(dictionary.All(pair => pair.Value < context.Builded.Vertices.Count)); var dictionary2 = new StackListQueue <KeyValuePair <Path, Vertex> >( dictionary.Select( pair => new KeyValuePair <Path, Vertex>(new Path(paths[pair.Key]), new Vertex(context.Builded.Vertices[pair.Value]))) ); var list = new StackListQueue <int>(dictionary.Select(pair => pair.Key).Distinct()); list.Sort(); Debug.Assert(dictionary2.All(pair => pair.Key.Count > 1)); for (int i = list.Count; i-- > 0;) { paths.RemoveAt(list[i]); } paths.AddRangeExcept( new PathCollection( dictionary2.SelectMany(pair => pair.Key.SplitBy(pair.Value) .Where(Path.IsNoVertix) .Where(Path.IsNoCircle)) .Distinct())); paths.ReplaceAll(paths.Distinct()); paths.RemoveAll(context.Builded.Contains); } } catch (Exception ex) { if (WorkerLog != null) { WorkerLog(ex.ToString()); } paths.ReplaceAll( paths.SelectMany(context.Builded.Split) .Where(Path.IsNoVertix) .Where(Path.IsNoCircle) ); paths.ReplaceAll(paths.Distinct()); paths.RemoveAll(context.Builded.Contains); } }
/// <summary> /// Разбиение пути в точках перечечения пути с графом на отдельные подпути /// </summary> /// <param name="path"></param> /// <returns></returns> public IEnumerable <Path> Split(Path path) { Debug.Assert(Count >= 2); var list = new StackListQueue <Path>(); StackListQueue <int> indexes; if (Settings.EnableCudafy) { try { int[,] matrix; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( Vertices.Select(path.GetInts).Select(item => item.ToArray()).ToArray(), path.GetRange(1, Count - 2).Select(path.GetInts).Select(item => item.ToArray()).ToArray() ); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = new StackListQueue <int>(CudafyMatrix.GetIndexes() .Where(index => index >= 0) .Select(index => index + 1)); } } catch (Exception ex) { Debug.WriteLine(ex.ToString()); indexes = new StackListQueue <int>( path.GetRange(1, Count - 2) .Intersect(Vertices) .Select(v => path.IndexOf(v))); } } else { indexes = new StackListQueue <int>( path.GetRange(1, Count - 2) .Intersect(Vertices) .Select(v => path.IndexOf(v))); } indexes.Sort(); indexes.Prepend(0); indexes.Append(Count - 1); Dictionary <Vertex, VertexSortedCollection> children = Children; for (int prev = indexes.Dequeue(); indexes.Any(); prev = indexes.Dequeue()) { if (((prev + 1) == indexes[0]) && children.ContainsKey(path[prev]) && children[path[prev]].Contains(path[indexes[0]])) { continue; } list.Add(new Path(path.GetRange(prev, indexes[0] - prev + 1))); } Debug.WriteLineIf(list.Any(), path + " split by " + this + " is " + string.Join(",", list.Select(item => item.ToString()))); return(list); }
public BooleanVector GetVector(Circle circle) { Debug.Assert(circle.Any()); int count = circle.Count; var collection = new SegmentCollection(); for (int i = 0; i < count; i++) { collection.Add(new Segment(circle[i], circle[(i + 1) % count])); } Debug.Assert(collection.All(Contains)); List <int> indexes; if (Settings.EnableCudafy) { try { IEnumerable <IEnumerable <int> > list1 = collection.Select(GetInts); IEnumerable <IEnumerable <int> > list2 = this.Select(GetInts); int[,] matrix; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( list1.Select(item => item.ToArray()).ToArray(), list2.Select(item => item.ToArray()).ToArray() ); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = CudafyMatrix.GetIndexes().ToList(); } } catch (Exception ex) { Debug.WriteLine(ex.ToString()); indexes = collection.Select(segment => IndexOf(segment)).ToList(); } } else { indexes = collection.Select(segment => IndexOf(segment)).ToList(); } indexes.Sort(); var booleanVector = new BooleanVector(); if (indexes[0] > 0) { booleanVector.AddRange(Enumerable.Repeat(false, indexes[0])); } booleanVector.Add(true); for (int i = 1; i < indexes.Count; i++) { if (indexes[i] - indexes[i - 1] > 1) { booleanVector.AddRange(Enumerable.Repeat(false, indexes[i] - indexes[i - 1] - 1)); } booleanVector.Add(true); } return(booleanVector); }
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 int Compare(StackListQueue <T> x, StackListQueue <T> y) { int[][] list1 = x.Select(x.GetInts).Select(i => i.ToArray()).ToArray(); int[][] list2 = y.Select(x.GetInts).Select(i => i.ToArray()).ToArray(); int value = list1.Length - list2.Length; if (value != 0) { return(value); } var list11 = new StackListQueue <StackListQueue <int> >(list1.Select(i => new StackListQueue <int>(i.Length))); var list22 = new StackListQueue <StackListQueue <int> >(list2.Select(i => new StackListQueue <int>(i.Length))); try { int[,] matrix; int first; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies(list11.Select(i => i.ToArray()).ToArray(), list22.Select(i => i.ToArray()).ToArray()); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRangeSelectFirstIndexOfNonNegative(); first = CudafyMatrix.GetFirst(); } if (first >= 0) { return(matrix[first, first]); } } catch (Exception exception) { value = list11.Select((c, i) => c[0] - list22[i][0]).FirstOrDefault(compare => compare != 0); if (value != 0) { return(value); } } try { int[,] matrix; int first; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies(list1, list2); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRangeSelectFirstIndexOfNonNegative(); first = CudafyMatrix.GetFirst(); } return((first < 0) ? 0 : matrix[first, first]); } catch (Exception exception) { return (list1.Select((t, i) => t.Select((item, j) => item - list2[i][j]) .FirstOrDefault(compare => compare != 0)) .FirstOrDefault(compare => compare != 0)); } }
public new IEnumerable <Path> Distinct() { if (Count == 0) { return(new MyLibrary.Collections.StackListQueue <Path>()); } if (Settings.EnableCudafy) { try { var list = new StackListQueue <StackListQueue <int> >( this.Select(path => new StackListQueue <int>(path.Select(vertex => vertex.Id)))); int[][] arr = list.Select(item => item.ToArray()).ToArray(); Debug.Assert(Count == arr.Length); int[,] matrix; int[] indexes; lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies(arr, arr); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } Debug.Assert(matrix.GetLength(0) == arr.Length); Debug.Assert(matrix.GetLength(1) == arr.Length); lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = CudafyMatrix.GetIndexes(); } Debug.Assert(indexes.GetLength(0) == arr.Length); IEnumerable <Path> paths1 = indexes.Where((value, index) => value == index) .Select(this.ElementAt); var list1 = new StackListQueue <StackListQueue <int> >( paths1.Select(path => new StackListQueue <int>(path.Select(vertex => vertex.Id)))); var list2 = new StackListQueue <StackListQueue <int> >( paths1.Select(path => new StackListQueue <int>(path.GetReverse().Select(vertex => vertex.Id)))); lock (CudafySequencies.Semaphore) { CudafySequencies.SetSequencies( list1.Select(item => item.ToArray()).ToArray(), list2.Select(item => item.ToArray()).ToArray() ); CudafySequencies.Execute("Compare"); matrix = CudafySequencies.GetMatrix(); } Debug.Assert(matrix.GetLength(0) == paths1.Count()); Debug.Assert(matrix.GetLength(1) == paths1.Count()); lock (CudafyMatrix.Semaphore) { CudafyMatrix.SetMatrix(matrix); CudafyMatrix.ExecuteRepeatZeroIndexOfZero(); indexes = CudafyMatrix.GetIndexes(); } Debug.Assert(indexes.GetLength(0) == paths1.Count()); return (new PathCollection( paths1.Where((value, index) => indexes[index] == -1 || indexes[index] >= index))); } catch (Exception ex) { return(new PathCollection(base.Distinct())); } } { return(new PathCollection(base.Distinct())); } }
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); } }