LINUX.ORG.RU

поиск подграфа в графе


0

1

Есть проблема с алгоритмом -

искомый подграф - subGraph
граф в котором ищем - graph
1* берем любую вершину в subGraph - v1
2* проходим по вершинам в graph и ищем одинаковую v1 вершину - v2, если нашли в 3*
3* Если v1 уже содержится в результате то пропускаем эту итерацию.
 Берём все исходящие вершины из v2 в graph и v1 в subGraph и ищем пересечение этих множеств.
 Если множество пусто(для какой либо из вершины v1 нет соответствующей v2) говорим что весь этот вариант не подходит иначе добавляем v1 и v2 в результат.

 Идём в 4* 
4* Выделяем это пересечение и по циклу с каждой парой вершин(или сответсвием одной вершины в subGraph с несколькими вершинами в graph) идём в 3*.

В итоге формируется всё множество подходящих подгафов в graph подграфу subGraph и затираются неподходящие(на каком-то шаге).
Структура алгоритма сильно упрощенна но смысл похож. Могу приложить реализацию, если надо, она на C#, для графов используется библиотека QuickGraph.

Проблема появилась с подграфом вида - http://xmages.net/show.php/1945929_123-jpg.html

Понимаю, что мало кому захочется разбираться, но может кто-то из присутствующих уже делал такое и может поделиться опытом(грабли какие там могут быть или ещё что).

п.с. циклы в графах я нахожу поиском вершины в уже добавленных

namespace OFTD.DOM.Graph
{
    public static class UndirectedGraphExtensions
    {
        public static IEnumerable<IDictionary<TVertex, TVertex>> SearchSubgraphs<TVertex, TEdge>(
            IUndirectedGraph<TVertex, TEdge> graph,
            IUndirectedGraph<TVertex, TEdge> visitedGraph)
            where TEdge : IUndirectedEdge<TVertex>
            where TVertex : Element
        {
            var allMatches = new List<List<Dictionary<TVertex, TVertex>>>();

            if ((graph.Vertices.Count() == 0) || (visitedGraph.Vertices.Count() == 0))
                return new List<IDictionary<TVertex, TVertex>>();// allMatches;

            var firstInVisited = visitedGraph.Vertices.First();
            foreach (var v in graph.Vertices)
            {
                if (equalp(v, firstInVisited))
                {
                    var dict = new Dictionary<TVertex, TVertex>();

                    var matchesFromThisVertex = new List<Dictionary<TVertex, TVertex>>();
                    matchesFromThisVertex.Add(dict);

                    allMatches.Add(matchesFromThisVertex);

                    searchIterations(ref matchesFromThisVertex, 0, graph, visitedGraph, firstInVisited, v, null, null);
                }
            }


            foreach (var list in allMatches)
            {
                list.RemoveAll(removeAllNullsDictionary);
            }
            allMatches.RemoveAll(removeAllEmptyList);
            var result = new List<IDictionary<TVertex, TVertex>>();
            foreach (var list in allMatches)
                foreach (var dictionary in list)
                    result.Add(dictionary);

            return result;
        }

        private static bool removeAllNullsDictionary<TVertex>(Dictionary<TVertex,TVertex> dict)
            where TVertex : Element
        {
            return (Equals(dict, null) || (dict.Count < 20));
        }

        private static bool removeAllEmptyList<TVertex>(List<Dictionary<TVertex, TVertex>> list)
            where TVertex : Element
        {
            return (list.Count == 0) ? true : false;
        }

        public static void searchIterations<TVertex, TEdge>(ref List<Dictionary<TVertex, TVertex>> matchs, int matchIndex,
            IUndirectedGraph<TVertex, TEdge> graph,
            IUndirectedGraph<TVertex, TEdge> visitedGraph,
            TVertex vgVert, TVertex gVert, TVertex previousVertexVg, TVertex previousVertexG)
            where TEdge : IUndirectedEdge<TVertex>
            where TVertex : Element
        {
            if(matchs.ElementAt(matchIndex) == null)
                return;
            if(matchs.ElementAt(matchIndex).ContainsKey(vgVert))
                return;

            matchs.ElementAt(matchIndex).Add(vgVert, gVert);

            var vgEdgesOuts = visitedGraph.AdjacentEdges(vgVert).ToList();
            var gEdgesOuts = graph.AdjacentEdges(gVert).ToList();
            var vgVertsOuts = getOutVertexes(vgVert, vgEdgesOuts);
            var gVertsOuts = getOutVertexes(gVert, gEdgesOuts);
     
            if(previousVertexVg != null)
            {
                vgVertsOuts.Remove(previousVertexVg);
                gVertsOuts.Remove(previousVertexG);
            }

            if (vgVertsOuts.Count == 0)
                return;
            if(gVertsOuts.Count == 0)
            {
                matchs[matchIndex] = null;
                return;
            }

            var intersectionsV = groupIntersectionVerts(vgVertsOuts, gVertsOuts);

            if(intersectionsV == null)
            {
                matchs[matchIndex] = null;
                return;
            } 
            
            var indexNext = matchIndex;
            foreach (var list in intersectionsV)
            {
                var tmpList = new List<TVertex>(list);
                tmpList.RemoveAt(0);
                foreach (var vertexInG in tmpList)
                {
                    if (indexNext > matchIndex)
                    {
                        var clonedDict = new Dictionary<TVertex, TVertex>(matchs.ElementAt(matchIndex));
                        matchs.Add(clonedDict);
                    }
                    searchIterations(ref matchs, indexNext, graph, visitedGraph, list.First(), vertexInG, vgVert, gVert);
                    indexNext++;
                }
            }
        }

        private static List<TVertex> getOutVertexes<TVertex, TEdge>(TVertex previousVert, List<TEdge> outsEdges)
            where TEdge : IUndirectedEdge<TVertex>
            where TVertex : Element
        {
            var outsVerts = new List<TVertex>();
            foreach (var edge in outsEdges)
            {
                if(edge.Source == previousVert)
                    outsVerts.Add(edge.Target);
                else
                    outsVerts.Add(edge.Source);
            }
            return outsVerts;
        }

        private static List<List<TVertex>> groupIntersectionVerts<TVertex>(List<TVertex> vs, List<TVertex> v)
            where TVertex : Element
        {
            var allIntersections = new List<List<TVertex>>();
            foreach (var svertex in vs)
            {
                var intersection = new List<TVertex>();
                intersection.Add(svertex);
                foreach (var vertex in v)
                {
                    if(equalp(svertex, vertex))
                        intersection.Add(vertex);
                }
                if (intersection.Count == 1)
                    return null;
                allIntersections.Add(intersection);
            }
            return allIntersections;
        }

        private static bool equalp<TVertex> (TVertex v1, TVertex v2)
            where TVertex : Element
        {
            return (string.Equals(v1.XmlName, v2.XmlName));
        }
    }
}

Прям какой-то день жавы на лоре. Слишком много букв, асилить сложно, перепиши на каком-нибудь более кратком языке, на haskell'е например.

Reset ★★★★★
()
Ответ на: комментарий от Jetty

словесное описание же) просто он - алгоритм, взяв правильные вершины за начальные предлагает более 4000 вариантов для нарисованного дерева, при том большая часть кривых. С другими деревьями работал нормально)

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от anonymous

Если это делать на boost graph library то еще большее уродство получится.

Reset ★★★★★
()

Какого вида графы? Если любого - то быстрого решения нет, т.к. задача проверки изоморфизма двух графов NP-полная, а она в свою очередь полиномиально сводится к твоей

anonymous
()
Ответ на: комментарий от anonymous

любого. Алгоритм, мною описанный, понятен? я могу его более подробно описать, если надо. Если понятен, то у меня есть вопрос -
* по-моему он подходит для любого вида графов. так или есть какие-то частные случаи, которые он не воспринимает(без учёта зацикливания и нескольких вариантов)?

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

Не понятно что такое «одинаковые» вершины. Бывает ли случай, когда вершина v1 subGraph «равна» вершинам v2 и v3 исходного графа? Если да, то на шаге 3 нужно брать все варианты пересечения данных множеств, иначе есть риск что-то пропустить.

А без зацикливания = дерево? Если да, то google «Изоморфизм деревьев». Там тоже не все так просто.

anonymous
()
Ответ на: комментарий от anonymous

Да, бывает. Именно поэтому возникают проблемы. Дело в том, что не все взаимные замены соответствий вершин икомого графа в графе, на котором ищем, корректны. Нужно проводить послеобработку результатов и выделять на них такие несоответсвия.

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

давайте когда время будет я опишу проблему более внятно

pseudo-cat ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.