2 ポイント 投稿者 GN⁺ 2024-03-05 | 1件のコメント | WhatsAppで共有

欠けているデータ型を求めて

  • グラフはノードの集合であり、矢印(エッジ)で接続される。
  • ノードとエッジにはデータを含められる。
  • ソフトウェアエンジニアリングにおいて、グラフはパッケージ依存関係、インターネットのリンク、ソフトウェアの状態空間、関係データベース、連結リスト、二分木、ハッシュテーブルなど、さまざまな形で存在する。
  • ビジネスロジックでも、グラフは引用の参照、交通ネットワーク、ソーシャルネットワークなどに活用される。
  • ソフトウェア開発を長くしていれば、どこであれグラフに出会う可能性が高い。

グラフ利用への悩み

  • グラフは有用だが、実際のコードでグラフを使うのは負担が大きい。
  • ほとんどの主要な言語ではグラフを組み込み型としてサポートしておらず、標準ライブラリでもまれで、堅牢なサードパーティライブラリも多くない。
  • グラフを自分で実装しなければならないことが多い。
  • ソフトウェアエンジニアがグラフを使える頻度と、プログラミングエコシステムにおける支援との間にはギャップがある。

グラフ型がない理由

設計上の選択肢が多すぎる

  • 有向グラフと無向グラフ、単純グラフと多重グラフ、ハイパーグラフ、ウーバーグラフなど、さまざまなグラフの種類が存在する。
  • 各種類について、ノードとエッジに ID を与えるか、どのようなデータを保存するかといった決定が必要になる。
  • あらゆる可能性をサポートする完璧なグラフライブラリには多くの時間が必要になる。
  • グラフアルゴリズムでは性能が重要であり、特殊なケースも重要になる。
  • グラフアルゴリズムを正しく実装するのは難しい。

実装上の選択肢が多すぎる

  • 単純な有向グラフだけをサポートすると仮定しても、グラフを内部的に表現する方法は複数ある。
  • エッジリスト、隣接リスト、隣接行列、構造体の集合など、さまざまな保存方式が存在する。
  • グラフ操作によって、表現方式ごとに異なる性能特性を持つ。
  • グラフの疎密に応じて、最適な内部表現は変わる。
  • ノードデータ、エッジデータ、さまざまな種類のノードやエッジを実装することはさらに複雑である。

性能が重要すぎる

  • 多くのグラフアルゴリズムは NP 完全問題か、それ以上に難しい。
  • グラフは非常に大きな問題になり得るため、表現方式やアルゴリズム実装の詳細によって性能が大きく変わる。
  • データ表現とアルゴリズムに対する多くの制御が必要になる。

一致した見解

  • 多様なグラフの種類、表現、アルゴリズム、性能への敏感さ、大規模グラフで高コストなアルゴリズムを実行することなどが、グラフ支援が広く普及していない理由である。
  • これは、言語が標準ライブラリでグラフをサポートしない理由を説明している。
  • これは、プログラマーがサードパーティのグラフライブラリを避ける理由を説明している。
  • グラフを使うのが難しいため、極端な状況でなければグラフとして考えたくない理由を説明している。

GN⁺の見解

  • この記事は、なぜグラフがプログラミング言語やライブラリで基本的なデータ型として定着しなかったのかについて洞察を与えてくれる。
  • グラフ理論はコンピュータサイエンスの重要分野であり、アルゴリズム、ネットワーク分析、データベースなど幅広い領域で応用されている。
  • グラフを効果的に使うには、性能最適化と適切なデータ構造の選択が重要である。
  • サードパーティライブラリとしては NetworkX、Boost Graph Library、Graph-tool などがあり、これらはさまざまなグラフ問題の解決に使える。
  • グラフを使う際には、問題の特性に合ったグラフの種類とアルゴリズムを選ぶことが重要であり、これはシステム性能に直結する。

1件のコメント

 
GN⁺ 2024-03-05
Hacker Newsのコメント
  • Graphviz は独自のグラフライブラリを持っており、これは他のプロジェクトでは使われていない。このライブラリには長所と短所がある。

    • この経験を通じて、彼らは自分たちなりの「第二システム症候群」を経験した。
    • グラフライブラリはモジュール式で、型安全で、効率的であるべきだと判断した。これは「良くて、速くて、安い――そのうち 2 つを選べ」という言葉の変形かもしれない。
    • モジュール式とは、独立して開発・コンパイルできるグラフアルゴリズムライブラリ群を書きたいという意味だ。
    • 型安全とは、コンパイル時、遅くともリンク時までにプログラミングエラーを検出したいという意味だ。実行時エラーは望んでいない。
    • 効率性とは、グラフの属性へのアクセスが C の構造体フィールドと同じくらい低コストであるべきだという意味だ。
    • こうした目標に価値があるかどうかは議論の余地があるが、それが彼らの望みだった。著名な C++ の生みの親たちが彼らの研究室にいたため、助けを得られるだろうと期待し、C++ にもう一度賭けてみることにした。
    • 元インターンの Gordon Woodhull は優れたプログラマで、テンプレート C++ でこの種のグラフライブラリを実装した。これは sourceforge を通じて https://www.dynagraph.org/ で公開された。
    • 他の人々はコードがどう動くのか理解できるか確信が持てなかったため、著名な C++ の発明者たちとコードレビューを行った。複雑性の崖を越えてしまったのかもしれないと分かった。
    • これは Gordon のせいではなく、彼はその後も取り組みを続け、Microsoft OLE 上でも動的グラフレイアウトの作業を成功させた。振り返れば、これは彼らにとってのプロジェクト・ザナドゥだったのかもしれない。
    • 彼らがこれに没頭している間に、Gephi (Java) や NetworkX、NetworKit (Python) のような多くのものが登場した。
    • John Ellson は Graphviz の一部を書いた非常に有能なソフトウェアエンジニアで、主要な取り組みを復活させた。
  • .NET でコーディングしているなら、小規模で機能は多くないがグラフライブラリの Arborescence を試してみてほしい。

    • このライブラリは、抽象化、アルゴリズム、データ構造の良い分離を提供していると思う。
    • ユーザーは独自 ID を持つエッジを使うことも、オンザフライで展開される暗黙的グラフを使うこともできる。
    • 隣接(外向きの近傍)インターフェースと、隣接(外向きエッジ + head)インターフェースの両方が使える。
    • ライブラリはエッジ型を強制しないが、基本的な tail-head ペア構造をユーティリティとして提供する。
  • グラフはデータ構造やデータ型ではなく、抽象化である。

    • 基本的に、グラフを定義するのに必要なのは頂点集合と近傍関数だけだ。
    • それ以外のものはすべて、ケースごとの制約条件にすぎない。
    • ハイパーグラフを考えれば、グラフは単なる特殊ケースにすぎない。
    • データベースの観点で考えるなら、グラフはクエリ最適化とインデックス付けの問題である。
  • プログラミング言語に組み込みのグラフデータ型がない理由について、これまで何度も質問されてきた。

    • いまでは、この文章のような、より踏み込んだ分析を示せるのがうれしい。
  • 中心的な障害は次のとおりだ:

    • 単純で小さなグラフ問題なら、ベクタのベクタによる隣接リストを実装するのは十分簡単だ。
    • 複雑で巨大なグラフ問題では、問題に合わせてグラフ実装をカスタマイズする以外に性能を得る方法がない。
    • どのような種類の言語サポートが役立つのかは明確ではない。
  • この記事は、プログラミング言語でグラフ アルゴリズム がより良くサポートされていない理由という問いに、ほぼ答えている。

    • グラフサポートを一般的に見れば、なぜ OGM が ORM ほど人気でないのか、なぜ JSON が RDF より広く使われているのか、といったより大きな問いも見えてくる。
    • 結局のところ、歴史的な理由とグラフの複雑さのために、開発者の間でうまくスケールしないのだ。
  • グラフ描画ツールも非常に残念だ。

    • 500 個を超えるノードを持つグラフでは、出力は理解しづらいか、過度に複雑になる。
    • グラフを階層構造として自動的に整理し、探索しやすいインターフェースを提供する機能が不足している。
  • この記事は本当に素晴らしい。

    • 「実装の選択肢が多すぎる」という核心的な観察について言えば、実際にはそうではない。
    • 実際には、ライブラリは適切なあらゆるグラフ表現を実装できる。
    • アルゴリズムを表現に合わせて調整し、ある表現から別の表現へ変換することもできる。
  • Electric Clojure は、Clojure 自身(s-式)をグラフ記述構文として使っている。

    • グラフ記述 DSL は、スコープ、制御フロー、抽象化を表現する必要があり、これは本質的にプログラミング言語そのものだ。
  • テーブル(データベース内のテーブルのような)という、もう 1 つの有用なデータ型がある。

    • コンパイラにデータ構造の実装を選ばせるようにすれば、プログラミング言語には進歩があるだろう。
    • 抽象構造(シーケンス、マップ、セット、テーブル、グラフなど)を使い、プログラムのプロファイルに基づいてコンパイラが具体的な実装を選択する。