Чтение GraphML в Haskell

Я пытаюсь прочитать файл GraphML, содержащий однонаправленный граф, в Haskell Data.Graph для запуска анализа с использованием Math.Combinatorics.Graph.

Однако я не могу найти модуль, который позволяет мне читать файл GraphML, создавая файл Data.Graph. Я нашел один связанный модуль: ForSyDe.Backend.GraphML. . Однако, похоже, это специфично для ForSyDe DSL, и в настоящее время я не могу придумать, как использовать его для чтения простого Data.Graph.

Не могли бы вы указать мне библиотеку, позволяющую мне читать GraphML, желательно с некоторым примером кода, как его использовать?


person Uli Köhler    schedule 10.01.2014    source источник
comment
GraphML — это просто XML, так почему бы не использовать один из множества парсеров XML для haskell (hxt, Haxml)? Быстрый поиск в Google ничего не дает для парсеров Haskell GraphML.   -  person user2407038    schedule 10.01.2014
comment
@ user2407038 Спасибо за ваше предложение! Если больше нечего использовать, я либо сделаю это, либо использую FFI для включения любой существующей библиотеки C/C++ GraphML, но моя основная проблема с ее разбором вручную (как XML) заключается в том, что она будет реализовывать только небольшое подмножество GraphML и, следовательно, может быть непригодным для использования, кроме как в некоторых очень специфических случаях использования.   -  person Uli Köhler    schedule 10.01.2014
comment
Почему синтаксический анализ XML реализует только небольшое подмножество? Я проверил спецификацию, и мне кажется, что это очень простой язык.   -  person user2407038    schedule 10.01.2014
comment
@user2407038 user2407038 У меня был опыт, когда большинство программ не строго соблюдают стандарт GraphML, некоторые библиотеки несовместимы друг с другом. Кроме того, такие функции, как гиперграфы, будет не так просто правильно реализовать, особенно без каких-либо пригодных для использования модульных тестов. Конечно, если такой библиотеки действительно нет, то это был бы лучший вариант.   -  person Uli Köhler    schedule 11.01.2014
comment
Что ж, если какое-то программное обеспечение не соответствует стандарту, вы мало что можете сделать. Я не знаю вашего сценария использования, но если ваша цель не состоит в том, чтобы создать синтаксический анализатор haskell graphML, вероятно, имеет смысл поддерживать только те части, которые вам понадобятся. Гиперграфы не кажутся такими сложными, учитывая, что в HaskellForMaths есть модуль гиперграфов. Вероятно, вам лучше всего написать минимальный синтаксический анализатор и идти дальше, добавляя функции по мере необходимости.   -  person user2407038    schedule 12.01.2014
comment
@user2407038 user2407038 Спасибо, я полностью согласен с вами, что это был бы лучший (если не единственный) подход. Я бы предпочел не делать этого (если бы для этой цели существовала библиотека), но, к сожалению, это не так.   -  person Uli Köhler    schedule 12.01.2014
comment
@user2407038 user2407038 Благодаря вашим предложениям мне удалось собрать минимальный парсер GraphML, который работает для некоторых тестовых графиков.   -  person Uli Köhler    schedule 21.01.2014


Ответы (1)


После более чем недели поиска я предполагаю, что в настоящее время не существует библиотеки синтаксического анализатора GraphML. Поэтому я написал свой минимальный парсер.

Предположим, у нас есть этот GraphML:

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
     http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  <graph id="G" edgedefault="undirected">
    <node id="n0"/>
    <node id="n1"/>
    <node id="n2"/>
    <node id="n3"/>
    <edge id="e1" source="n0" target="n1"/>
    <edge id="e1" source="n1" target="n2"/>
    <edge id="e1" source="n1" target="n3"/>
    <edge id="e1" source="n3" target="n0"/>
  </graph>
</graphml>

Я создал этот синтаксический анализатор на основе HXT, способный анализировать минимальное подмножество GraphML (достаточно для создания Data.Graph вышеприведенного GraphML). Функция main из следующего файла представляет собой пример ее использования: она выводит список узлов в графе (см. также этот связанный вопрос ).

{-# LANGUAGE Arrows, NoMonomorphismRestriction #-}
import Text.XML.HXT.Core
import qualified Data.Graph as DataGraph

data Graph = Graph
  { graphId :: String,
    nodes :: [String],
    edges :: [(String, String)] -- (Source, target)
  }
  deriving (Show, Eq)

atTag tag = deep (isElem >>> hasName tag)

parseEdges = atTag "edge" >>>
  proc e -> do
      source <- getAttrValue "source" -< e
      target <- getAttrValue "target" -< e
      returnA -< (source, target)

parseNodes = atTag "node" >>>
  proc n -> do
      nodeId <- getAttrValue "id" -< n
      returnA -< nodeId

parseGraph = atTag "graph" >>>
  proc g -> do
      graphId <- getAttrValue "id" -< g
      nodes <- listA parseNodes -< g
      edges <- listA parseEdges -< g
      returnA -< Graph{graphId=graphId, nodes=nodes, edges=edges}

getEdges = atTag "edge" >>> getAttrValue "source"

-- Get targets for a single node in a Graph
getTargets :: String -> Graph -> [String]
getTargets source graph = map snd $ filter ((==source).fst) $ edges graph

-- Convert a graph node into a Data.Graph-usable
getDataGraphNode :: Graph -> String -> (String, String, [String])
getDataGraphNode graph node = (node, node, getTargets node graph)

-- Convert a Graph instance into a Data.Graph list of (node, nodeid, edge) tuples
getDataGraphNodeList :: Graph -> [(String, String, [String])]
getDataGraphNodeList graph = map (getDataGraphNode graph) (nodes graph)

main :: IO()
main = do
    graphs <- runX (readDocument [withValidate no] "foo.graphml" >>> parseGraph)
    --  Convert Graph structure to Data.Graph-importable tuple list
    let graphEdges = getDataGraphNodeList $ head graphs
    -- Convert to a Data.Graph
    let (graph, vertexMap) = DataGraph.graphFromEdges' graphEdges
    -- Example of what to do with the Graph: Print vertices
    print $ map ((\ (vid, _, _) -> vid) . vertexMap) (DataGraph.vertices graph)
person Uli Köhler    schedule 21.01.2014