使用JGraphT 1.4.0版本导入一个以其元素作为标签的边列表图。

huangapple go评论95阅读模式
英文:

Import a edgelist graph using its elements as labels with JGraphT 1.4.0

问题

我将自己的项目从 JGraphT 1.3.1 更新到了 1.4.0,并注意到引入了一个新的 org.jgrapht.nio 包来处理输入输出;我考虑切换到它,因为基本上 org.jgrapht.io 已经被弃用,而且我希望我的工作在未来的一些年里是兼容的。

我的问题是,在替换了被弃用的类之后,边缘列表如下:

a b
b c
b d
a d

(其中空格字符被设置为分隔符)不再像字母字符一样导入标签,而是作为索引出现,即上述边缘列表变为:

0 1
1 2
1 3
0 3

你可以通过获取 CSVImporterTest.java 测试类,并在其中的一个测试方法中将其节点替换为字母字符,以重现此行为:测试将失败,因为当图由构建器创建时,顶点供应者由 SupplierUtil.createStringSupplier(1) 调用给出,该调用基本上会生成字符串形式的数字,而不是从边缘列表中选择顶点。

由于关于序列化的 用户指南 尚未更新为 1.4.0 版本,并且不包括使用 org.jgrapht.nio 包的任何示例,而且我显然对如何恢复 org.jgrapht.io.CSVImporter 的行为一无所知,我应该如何实际从边缘列表中读取节点,而不仅仅是计数呢?我是否需要添加一些额外的处理来将这些索引转换回字母字符?

我甚至尝试过自己构建一个 lambda 函数,因为构建器 vertexSupplier(Supplier<T>) 接受一个 Supplier<T> 作为其输入,但我卡在了 () -> T t 这一步,其中 t 显然是未定义的,并且应该从文件中获取。

英文:

I updated a project of mine from JGraphT 1.3.1 to 1.4.0 and noticed that a new org.jgrapht.nio package has been introduced for I/O; I thought to switch to it, since basically org.jgrapht.io has been deprecated and I'd like my work to be future-proof for some years on.

My problem is, after replacing deprecated classes, that edge lists like

a b
b c
b d
a d

(where blank character is set as separator) are no more imported with labels as alphabetic characters but as indexed occurrences, i.e. the above edge list becomes

0 1
1 2
1 3
0 3

You may reproduce this behaviour by taking the CSVImporterTest.java test class and replacing its nodes in one of its test methods with alphabetic characters: the test will fail because then the graph is created by the builder, the vertex supplier is given by SupplierUtil.createStringSupplier(1) invocation that basically generates numbers as strings instead of picking vertices from edge list.

Since user guide about serialization hasn't been updated to 1.4.0 yet and doesn't include any example of use of org.jgrapht.nio package, and since it's plain clear I didn't get a thing about how to restore the behaviour of org.jgrapht.io.CSVImporter, how am I suppose to actually read nodes from edge list instead of counting them? Do I have to add some more processing to convert those indexes back to alphabetic letters?

I even tried to build a lambda function by myself, since builder vertexSupplier(Supplier&lt;T&gt;) takes a Supplier&lt;T&gt; as its input, but I got stuck at () -&gt; T t, where t is clearly undefined and should be taken somewhere from file.

答案1

得分: 0

新的 I/O 包已经从头重新设计,并且在图的创建过程中确实改变了语义。这主要是将包名称从 org.jgrapht.io 更改为 org.jgrapht.nio 的原因。

在过去的几年中,通过使用图顶点和边供应商,图中的顶点/边创建得到了改进。新的 I/O 导入器切换了行为,并在需要新顶点时调用 Graph#addVertex(),从而使用提供的图顶点供应商创建顶点。

不幸的是,这导致了您观察到的行为。输入文件中的实际顶点标识仍然可访问,因为它们被视为顶点属性,并且在导入过程中使用“ID”的键进行报告。

另请参见 https://stackoverflow.com/questions/60461351/import-graph-with-1-4-0,这是一个非常类似的案例,并使用此功能创建具有完全相同标识符的第二个图。

另一方面,旧的行为是有意义的。可以自然地期望导入保留您的顶点标识符(至少对于大多数导入器来说)。已经有一个修复方法,通过提供一个方法 #setVertexFactory(Function) 来实现。该方法允许用户通过提供自定义的顶点工厂方法来绕过顶点创建。工厂方法负责根据从输入文件中读取的顶点标识符创建新的图顶点。

修复将在下一个版本中可用(可能是 1.4.1),并且已经在快照构建中可用(1.4.1-SNAPSHOT)。请参阅 https://github.com/jgrapht/jgrapht#using-via-maven 以了解如何使用快照构建。

为了保留旧的行为,您应该构建类似以下方式的导入器:

CSVImporter<String, DefaultEdge> importer = new CSVImporter<>();
importer.setVertexFactory(id -> id);
importer.importGraph(g, new StringReader(input));
英文:

The new I/O package was redesigned from scratch and indeed it changes the semantics during graph creation. This is mainly the reason for switching package names from org.jgrapht.io to org.jgrapht.nio.

During the last years vertex/edge creation has been improved in the graphs using graph vertex and edge suppliers. The new I/O importers switch behavior and call Graph#addVertex() whenever a new vertex is required, which in turn uses the provided graph vertex supplier to create the vertex.

Unfortunately this leads to your observed behavior. The actual vertex identifiers from the input file are still accessible as they are considered vertex attributes and are reported during import using a key of "ID".

See also https://stackoverflow.com/questions/60461351/import-graph-with-1-4-0 which is a very similar case and uses this functionality to create a second graph with the exact same identifiers.

On the other hand, the old behavior makes sense. It is natural to expect that the import retains your vertex identifiers (at least for most importers). There is already a fix for this by providing a method #setVertexFactory(Function). This method allows the user to bypass vertex creation by providing a custom vertex factory method. The factory method is responsible to create a new graph vertex given the vertex identifier read from the input file.

The fix will be available in the next release (probably 1.4.1) and is already available in the snapshot build (1.4.1-SNAPSHOT). See https://github.com/jgrapht/jgrapht#using-via-maven on how to use the snapshot build.

In order to retain the old behavior you should build your importer like:

CSVImporter&lt;String, DefaultEdge&gt; importer = new CSVImporter&lt;&gt;();
importer.setVertexFactory(id-&gt;id);
importer.importGraph(g, new StringReader(input));

huangapple
  • 本文由 发表于 2020年4月8日 05:22:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/61089620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定