Jgrapht: NaiveLcaFinderのバグ

作成日 2018年02月14日  ·  13コメント  ·  ソース: jgrapht/jgrapht

みなさん、こんにちは。ドットファイルを解析しようとしているときに、すべてのLCAがRobertCerseiであるはずのグラフを使用しましたが、代わりに何も受け取りませんでした。 本当にバグか確認してください。 このバグは、NaiveLcaFinderの関数findLcasにあります。

<strong i="9">@Test</strong>
    public void testPseudoLcas(){
     public final String NL = "\n";
        String input = "digraph GOT {"+NL+
            "graph [ bgcolor = whitesmoke ]"+NL+
            "subgraph cluster_stark {"+NL+
                "style = filled ;"+NL+
                "color = lightblue ;"+NL+
                "label = \" House Stark \" ;"+NL+
                "node [ style = filled , color = white ];"+NL+
                "Rickard ;"+NL+
                "Brandon ; Eddard ; Benjen ; Lyanna ;"+NL+
                "Robb ; Sansa ; Arya ; Brandon ; Rickon ;"+NL+
                "node [ shape = doublecircle , style = filled , color = white ];"+NL+
                "Jon ;"+NL+
                "Rickard -> Brandon ;"+NL+
                "Rickard -> Eddard ;"+NL+
                "Rickard -> Benjen ;"+NL+
                "Rickard -> Lyanna ;"+NL+
                "Eddard -> Robb ;"+NL+
                "Eddard -> Sansa ;"+NL+
                "Eddard -> Arya ;"+NL+
                "Eddard -> Brandon ;"+NL+
                "Eddard -> Rickon ;"+NL+
                "Eddard -> Jon [ label = \" bastard \" , color = azure4 ];"+NL+
            "}"+NL+
            "subgraph cluster_baratheon {"+NL+
                "style = filled ;" +NL+
                "color = chocolate3 ;" +NL+
                "label = \" House Baratheon \" ;" +NL+
                "node [ style = filled , color = white ];" +NL+
                "Ormund ; Steffon ; Robert ; Stannis ; Renly ; Shireen ; Joffrey ; Myrcellar ; Tommen ;" +NL+
                "Ormund -> Steffon ;" +NL+
                "Rhaelle -> Steffon ;" +NL+
                "Ormund -> Rhaelle ;" +NL+
                "Rhaelle -> Ormund ;" +NL+
                "Steffon -> Robert ;" +NL+
                "Steffon -> Stannis ;" +NL+
                "Steffon -> Renly ;" +NL+
                "Stannis -> Shireen ;" +NL+
                "Robert -> Joffrey ;" +NL+
                "Robert -> Myrcellar ;" +NL+
                "Robert -> Tommen ;" +NL+
            "}" +NL+
            "subgraph cluster_lannister {"+NL+
                "style = filled ;"+NL+
                "color = cornsilk3 ;"+NL+
                "label = \" House Lannister \" ;"+NL+
                "node [ style = filled , color = white ];"+NL+
                "Tywin ; Joanna ; Jaime ; Cersei ; Tyrion ;"+NL+
                "Tywin -> Joanna ;"+NL+
                "Joanna -> Tywin ;"+NL+
                "Joanna -> Jaime ;"+NL+
                "Joanna -> Cersei ;"+NL+
                "Joanna -> Tyrion ;"+NL+
                "Tywin -> Jaime ;"+NL+
                "Tywin -> Cersei ;"+NL+
                "Tywin -> Tyrion ;"+NL+
                "Jaime -> Cersei ;"+NL+
                "Cersei -> Jaime ;"+NL+
                "Robert -> Cersei ;"+NL+
                "Cersei -> Robert ;"+NL+
                "Cersei -> Joffrey ;"+NL+
                "Cersei -> Myrcellar ;"+NL+
                "Cersei -> Tommen ;"+NL+
                "Jaime -> Joffrey [ style = dashed ];"+NL+
                "Jaime -> Myrcellar [ style = dashed ];"+NL+
                "Jaime -> Tommen [ style = dashed ];"+NL+
            "}"+NL+
            "Lyanna -> Rhaegar [ style = dashed , label = \" ? \" ];"+NL+
            "Rhaegar -> Lyanna [ style = dashed , label = \" ? \" ];"+NL+
            "Lyanna -> Jon [ style = dashed , label = \" ? \" ];"+NL+
            "Rhaegar -> Jon [ style = dashed , label = \" ? \" ];"+NL+
            "labelloc = \" t \" ;"+NL+
            "fontsize =50;"+NL+
            "fontcolor = lightslategrey ;"+NL+
            "fontname = \" Bookman Old Style Bold Italic \" ;"+NL+
            "label = \" Game of Thrones Family Tree \""+NL+
            "}" ; 

            VertexProvider<String> vp = (a, b) -> a;
        EdgeProvider<String, DefaultEdge> ep = (f, t, l, a) -> new DefaultEdge();
        GraphImporter<String, DefaultEdge> importer = new DOTImporter<String, DefaultEdge>(vp, ep);
        DirectedPseudograph<String, DefaultEdge> graph = new DirectedPseudograph<String, DefaultEdge>(DefaultEdge.class);
        try {
            importer.importGraph(graph, new StringReader(input));
        } catch (ImportException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    NaiveLcaFinder<String, DefaultEdge> graphFinder = new NaiveLcaFinder<>(graph);
        checkLcas(graphFinder, "Joffrey", "Tommen", Arrays.asList("Robert"));
    }

全てのコメント13件

この問題をデバッグするために何をしましたか?

NaiveLcaFinderクラスのコンストラクターは、グラフを方向付ける必要があることを確認するだけであり、グラフにサイクルが含まれているかどうかはチェックしません。 LCAはDAGで検出する必要がありますが、特定のテストで、後でDAGではないことに気付きました。 DAGであるはずでしたが、そうではありませんでした。 先に進んでこのチェックを実装する必要がありますか?

いいえ、これをチェックとして追加するのは良い考えではありません。 入力の検証に計算の労力を費やすことと、ユーザーが正しい入力を提供すると仮定することの間には、常にトレードオフがあります。 私は現在コードにアクセスできませんが、あなたができることは次のとおりです。

  1. GraphTestsにメソッドisDirectedAcyclicGraphが含まれているかどうかを確認します。 そうでない場合は、追加します。
  2. NaiveLCAコードで、アサーションを追加します。assertGraphTests.isDirectedAcyclicGraph(g); おそらくNaiveLCAでは、入力グラフがDAGである必要があることを、ドキュメント/パラメーターの仕様でより明確にする必要があります。
  3. jgraphtには、グラフが非巡回であるかどうかをアサートするために使用できるアルゴリズムがたくさんあるので、それを実装する必要はありません。

それでも、isDirectedAcyclicGraphテストに相当するメソッドがまだ存在しないかどうかを再確認してください(これは心からはわかりません)。

私のプロジェクトでは、暫定的に、DAGを要求するようにNaiveLcaFinderコンストラクターを変更しました。 メソッドisDirectedAcyclicGraphの記述に取り組みます。 グラフが指示されている場合とグラフにサイクルが含まれている場合の両方の実装がすでにあるので、 isDirectedAcyclicGraphの実装に進むことができますか?

@ hulk-baba入力ファイルに問題があります。 「RobertCersei」(実際には正しくありませんが、CerseiからRobertへのエッジがあります。入力ファイルのRobertからCerseiへのエッジがあります)を入力として使用し実装を実行すると、Cerseiが取得されます。ファイル。

入力ファイルをもう一度確認して、何かが見つかった場合はお知らせください(または、Lannister / Baratheonサブグラフの一部をシミュレートした小さなグラフを試してみてください。デバッグが簡単です)。

@AlexandruValeanuコードcheckLcas(graphFinder, "Joffrey", "Tommen", Arrays.asList("Robert")); のように、異なる引数Joffrey Tommenを使用して同じ入力ファイルで試してください

@ hulk-babaその通りです。 その場合は機能しません。

共通の祖先のセットは[Robert, Cersei, Jaime]になります。 しかし、その後、これが起こります。 そのコードは、祖先のセットに子を持つすべてのノードを削除します。 CerseiからRobertとJaime、RobertからCerseiにはエッジがあるため、3つすべてを共通の祖先のセットから削除できます(CerseiはRobertのために削除され、JaimeはCerseiのために、RobertはCerseiのために削除されます) 。

グラフはDAGではないため、これは実際の実装では問題になりません(RobertとCerseiの間のサイクルにより、Lannister / Baratheonサブグラフで問題が発生します)。

考えられる修正:

  • ロバートからセルセイまでの端を取り除きます。 端を取り除いた後、「ロバート」が表示されます
  • この場合、findLcaは機能します。 他のサイクルでは機能しない可能性がありますが、このサイクルでは機能するようです
  • サイクルのあるグラフでより良いパフォーマンスを発揮するように私が行うことができる小さな修正がありますが、これはこの実装の目的ではありません

@AlexandruValeanuでは、与えられたグラフが正しくないと仮定して、 RobertからCerseiにエッジを削除しているのでしょうか。
コードが現在実行している循環グラフの場合、出力はないはずだと思いますが、 JoffreyCerseiを入力すると、出力はCerseiになります。 Cerseiはサイクルの一部であり、そのノードがLCAであるかどうかを確認できないため、これは適切ではないと思います。
したがって、私が提案するのは、関数detectCyclesContainingVertexを呼び出すことで、入力ノードがサイクルの一部であるかどうかを確認でき、それらのいずれかがtrueの場合、LCAなしで戻ることができるということです。 これは、ウォーミングアップの演習で行っていることです。
私がこれを間違って理解したかどうか私に知らせて、私がそれを正しくするのを手伝ってください。

@ tibrewalpratik17
そのpdfのグラフはDAGではないため、何も想定する必要はありません。 NaiveLcaFinderへの有効な入力ではありません

ウォームアップの課題については、グラフを変更して、サイクルが含まれないようにすることをお勧めします。 CycleDetectorを使用して、グラフのバージョンにサイクルがあるかどうかを確認できます。

私のfindLcasの実装では、循環グラフが与えられたときに、循環を検出したり、賢明な答えを生成するために賢明なことをしたりしません(つまり、 undefined behaviourを取得します)。 したがって、前提条件が破られた場合、出力を分析しても意味がありません。

@AlexandruValeanu大丈夫です...しかし、ユーザーが循環グラフを入力して出力を期待している場合はどうなりますか?その場合の有効な出力は、特定のノードの最近の祖先のいずれか、またはノード自体がサイクルに関与している場合はnullになります正しい?

ユーザーは答えを期待するべきではありません。その場合、ユーザーは入力を検証する必要があります。これは、fの定義域ではなく、入力xのf(x)と同じであり、答えはnullではありませんが定義されていません。

@ tibrewalpratik17
NaiveLcaFinderは、DAGが渡された場合にのみ、lcasの正しいリストを返します。

入力がDAGでない場合、出力は信頼されるべきではありません。 文字通り何でもかまいません。 この場合、私の実装はサイクルの一部ではないlcasのみを返すと思いますが、答えがどのようにundefinedであるかをテストしていないため、実際にはわかりません。

バグではないので、誰かがこれを閉じてもらえますか?

このページは役に立ちましたか?
0 / 5 - 0 評価