Использование идентификаторов вершинных строк в качестве фактических вершин при импорте графа (jgrapht 1.4) - PullRequest
0 голосов
/ 29 февраля 2020

У меня очень простой график

strict digraph G {
  <assembly-raw-file>;
  <dataset-processing>;
  <feature-processing-1>;
  <feature-processing-2>;
  <mh.permute-variables-and-hyper-params>;
  <mh.finish>;
  <assembly-raw-file> -> <dataset-processing>;
  <dataset-processing> -> <feature-processing-1>;
  <dataset-processing> -> <feature-processing-2>;
  <dataset-processing> -> <mh.permute-variables-and-hyper-params>;
  <feature-processing-1> -> <mh.permute-variables-and-hyper-params>;
  <feature-processing-2> -> <mh.permute-variables-and-hyper-params>;
  <mh.permute-variables-and-hyper-params> -> <mh.finish>;
}

Я пытаюсь импортировать его с помощью следующего кода

DirectedAcyclicGraph<String, DefaultEdge> processGraph = new DirectedAcyclicGraph<>(
        SupplierUtil.createStringSupplier(), SupplierUtil.DEFAULT_EDGE_SUPPLIER, false);

DOTImporter<String, DefaultEdge> importer = new DOTImporter<>();
importer.importGraph(processGraph, new StringReader(wpy.processesGraph));

, но этот код меняет имена вершин на следующие:

strict digraph G {
  0;
  1;
  2;
  3;
  4;
  5;
  0 -> 1;
  1 -> 2;
  1 -> 3;
  1 -> 4;
  2 -> 4;
  3 -> 4;
  4 -> 5;
}

Как импортировать мой граф с сохранением идентификатора вершин?

Или более простое решение - изменить тип вершины со строки на сложный класс?

1 Ответ

0 голосов
/ 29 февраля 2020

Обновление от 4 марта 2020 года:

Если вы используете версию 1.4.1 SNAPSHOT (или более позднюю), есть более простой способ получить желаемый результат: просто используйте importer.setVertexFactory(id->id);

Только в случае, если пользователь поставляет, например, фабрику, он вызывается с идентификатором вершины из файла. Метод, предоставляющий идентификатор вершины из файла, должен возвращать фактическую вершину графа. Вершина, возвращаемая пользователем, добавляется непосредственно в граф без использования поставщика вершин.

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

Применяя это к приведенному выше примеру, мы получаем:

String input="strict digraph G {\n" +
        "  <assembly-raw-file>;\n" +
        "  <dataset-processing>;\n" +
        "  <feature-processing-1>;\n" +
        "  <feature-processing-2>;\n" +
        "  <mh.permute-variables-and-hyper-params>;\n" +
        "  <mh.finish>;\n" +
        "  <assembly-raw-file> -> <dataset-processing>;\n" +
        "  <dataset-processing> -> <feature-processing-1>;\n" +
        "  <dataset-processing> -> <feature-processing-2>;\n" +
        "  <dataset-processing> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <feature-processing-1> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <feature-processing-2> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <mh.permute-variables-and-hyper-params> -> <mh.finish>;\n" +
        "}";
Graph<String, DefaultEdge> graph = new SimpleDirectedGraph<>(DefaultEdge.class);
DOTImporter<String, DefaultEdge> importer = new DOTImporter<>();
importer.setVertexFactory(id->id);
importer.importGraph(graph, new StringReader(input));
System.out.println(graph);

Исходный ответ:

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

String input="strict digraph G {\n" +
        "  <assembly-raw-file>;\n" +
        "  <dataset-processing>;\n" +
        "  <feature-processing-1>;\n" +
        "  <feature-processing-2>;\n" +
        "  <mh.permute-variables-and-hyper-params>;\n" +
        "  <mh.finish>;\n" +
        "  <assembly-raw-file> -> <dataset-processing>;\n" +
        "  <dataset-processing> -> <feature-processing-1>;\n" +
        "  <dataset-processing> -> <feature-processing-2>;\n" +
        "  <dataset-processing> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <feature-processing-1> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <feature-processing-2> -> <mh.permute-variables-and-hyper-params>;\n" +
        "  <mh.permute-variables-and-hyper-params> -> <mh.finish>;\n" +
        "}";
Graph<String, DefaultEdge> graph = new SimpleDirectedGraph<>(SupplierUtil.createStringSupplier(), SupplierUtil.DEFAULT_EDGE_SUPPLIER, false);

//Import the graph; the vertex names are stored as 'ID' in the attribute map
DOTImporter<String, DefaultEdge> importer = new DOTImporter<>();
Map<String, Map<String, Attribute>> attrs = new HashMap<>();
importer.addVertexAttributeConsumer((p, a) -> {
    Map<String, Attribute> map = attrs.computeIfAbsent(p.getFirst(), k -> new HashMap<>());
    map.put(p.getSecond(), a);
});
importer.importGraph(graph, new StringReader(input));

//Create a new graph, thereby creating String vertices equal to the ID attribute values
Graph<String,DefaultEdge> labeledGraph=new SimpleDirectedGraph<>(DefaultEdge.class);
for(String v : graph.vertexSet())
    labeledGraph.addVertex(attrs.get(v).get("ID").getValue());
for(DefaultEdge e : graph.edgeSet()){
    String source = graph.getEdgeSource(e);
    String target = graph.getEdgeTarget(e);
    String sourceID=attrs.get(source).get("ID").getValue();
    String targetID=attrs.get(target).get("ID").getValue();
    labeledGraph.addEdge(sourceID, targetID);
}

System.out.println(labeledGraph);
...