示例#1
0
        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);
                            }
                        }