誰かが簡単な言葉で有向非巡回グラフとは何かを説明できますか?私はウィキペディアを調べましたが、プログラミングでの使用を実際に確認することはできません。
誰かが簡単な言葉で有向非巡回グラフとは何かを説明できますか?私はウィキペディアを調べましたが、プログラミングでの使用を実際に確認することはできません。
回答:
グラフ=エッジで相互に接続されたノードで構成される構造
有向=ノード(エッジ)間の接続には方向があります:A-> BはBと同じではありません-> A
acyclic = "non-circular" =エッジに沿ってノードからノードに移動すると、同じノードに2回目に遭遇することはありません。
有向非循環グラフの良い例はツリーです。ただし、すべての有向非循環グラフがツリーであるとは限りません。
DAG(有向非巡回グラフ)の意味を示す多くの回答が表示されますが、そのアプリケーションについては回答がありません。これは非常にシンプルなものです-
前提条件のグラフ -工学コースでは、すべての学生が前提条件などの要件に従う科目を選択する課題に直面します。アルゴリズム[A]の必須コースがないと、人工知能[B]のクラスを受講できないことは明らかです。したがって、BはAに依存します。つまり、AはBに向けられたエッジを持っています。ノードBに到達するには、ノードAにアクセスする必要があります。前提条件を持つすべてのサブジェクトをグラフに追加すると、すぐに明らかになります、それは有向非巡回グラフであることが判明します。
サイクルがあった場合、コースを完了することはありません:p
学生がコースに登録できる大学のソフトウェアシステムは、学生が現在のコースに登録する前に必須のコースを受講していることを確認するために、ノードとして科目をモデル化できます。
私の教授はこのアナロジーを与えました、そしてそれは私がいくつかの複雑な概念を使うよりもDAGを理解するのに最も役立ちました!
別のリアルタイムの例-> DAGをバージョンシステムで使用する方法のリアルタイムの例
プログラミングにおける有向非循環グラフの使用例には、接続性と因果関係を表す多かれ少なかれ何でも含まれます。
たとえば、実行時に構成可能な計算パイプラインがあるとします。この1つの例として、計算A、B、C、D、E、F、およびGが互いに依存しているとします。AはCに依存し、CはEおよびFに依存し、BはDおよびEに依存し、DはF.これはDAGとして表すことができます。DAGをメモリに格納したら、次のアルゴリズムを記述できます。
他の多くのものの間で。
アプリケーションプログラミングの領域外では、適切な自動ビルドツール(make、ant、sconsなど)はDAGを使用して、プログラムのコンポーネントの適切なビルド順序を保証します。
いくつかの回答がグラフの使用例(ネットワークモデリングなど)を示しており、「これはプログラミングとどのような関係があるのか」と尋ねました。
そのサブ質問への答えは、プログラミングとはほとんど何の関係もないということです。それは問題解決と関係があります。
リンクリストが特定のクラスの問題に使用されるデータ構造であるように、グラフは特定の関係を表すのに役立ちます。リンクされたリスト、ツリー、グラフ、およびその他の抽象的な構造は、それらをコードで実装できるという点でプログラミングにのみ関連しています。それらはより高い抽象化レベルで存在します。それはプログラミングではなく、問題の解決にデータ構造を適用することです。
有向非巡回グラフ(DAG)には、他のグラフと区別する次のプロパティがあります。
さて、私は今のところ1つの使用法を考えることができます-DAG(Wait-For-Graphsとして知られている -より技術的な詳細)は、プロセスとリソースのセット(どちらもDAGのノードです)間の依存関係を示しているため、デッドロックを検出するのに便利です。サイクルが検出されるとデッドロックが発生します。
基本的なグラフの用語をすでに知っていると思います。それ以外の場合は、グラフ理論に関する記事から始める必要があります。
有向とは、エッジ(接続)に方向があることを指します。図では、これらの方向が矢印で示されています。反対は無向グラフで、そのエッジは方向を指定しません。
非循環とは、任意のノードXから開始してすべての可能なエッジをウォークスルーした場合、すでに使用されているエッジに戻ることなくXに戻ることができないことを意味します。
いくつかのアプリケーション:
DAGはすべてが同じ方向に流れ、どのノードもそれ自体を参照できないグラフです。
祖先の木について考えてください。それらは実際にはDAGです。
すべてのDAGには
DAGはツリーとは異なります。ツリーのような構造では、2つのノードすべての間に一意のパスが必要です。DAGでは、ノードは2つの親ノードを持つことができます。
DAGに関する優れた記事を次に示します。お役に立てば幸いです。
あらゆる種類のグラフがプログラミングで使用され、さまざまな異なる実世界の関係をモデル化します。たとえば、ソーシャルネットワークは多くの場合、グラフ(この場合は周期的)で表されます。同様に、ネットワークトポロジ、家系図、航空路線、...
ソースコードまたは3つのアドレス(TAC)コードの観点からも、このページで問題を簡単に視覚化できます...
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
式ツリーのセクションに移動して、ページを少し下に移動すると、ツリーの「トポロジカルソート」と、式を評価する方法のアルゴリズムが表示されます。
したがって、その場合、DAGを使用して式を評価できます。これは、評価が通常解釈され、そのようなDAGエバリュエーターを使用すると、スタックへのプッシュとポップが行われないため、また、排除されるため、基本的にシンプルなインタープリターが高速になります。一般的な部分式。
非古代エジプト(つまり英語)でDAGを計算する基本的なアルゴリズムは次のとおりです。
1)DAGオブジェクトを次のようにします
ライブリストが必要です。このリストには、現在のすべてのライブDAGノードとDAGサブ式が保持されます。DAGサブ式はDAGノードですが、内部ノードと呼ぶこともできます。ライブDAGノードとは、変数Xに割り当てるとライブになるということです。Xを使用する一般的な部分式は、そのインスタンスを使用します。Xが再度割り当てられると、NEW DAG NODEが作成されてライブリストに追加され、古いXが削除されるため、Xを使用する次のサブ式は新しいインスタンスを参照し、したがって、次のサブ式と競合しません。同じ変数名を使用するだけです。
変数Xに割り当てると、偶然にも、新しい割り当てによって古い値を使用するサブ式の意味が無効になるため、割り当ての時点でライブであるすべてのDAGサブ式ノードが非アクティブになります。
class Dag {
TList LiveList;
DagNode Root;
}
// In your DagNode you need a way to refer to the original things that
// the DAG is computed from. In this case I just assume an integer index
// into the list of variables and also an integer index for the opertor for
// Nodes that refer to operators. Obviously you can create sub-classes for
// different kinds of Dag Nodes.
class DagNode {
int Variable;
int Operator;// You can also use a class
DagNode Left;
DagNode Right;
DagNodeList Parents;
}
したがって、ソースコード内の式のツリーなど、独自のコードでツリーをウォークスルーします。たとえば、既存のノードをXNodesと呼びます。
そのため、XNodeごとに、DAGに追加する方法を決定する必要があり、それがすでにDAGにある可能性があります。
これは非常に単純な疑似コードです。コンパイル用ではありません。
DagNode XNode::GetDagNode(Dag dag) {
if (XNode.IsAssignment) {
// The assignment is a special case. A common sub expression is not
// formed by the assignment since it creates a new value.
// Evaluate the right hand side like normal
XNode.RightXNode.GetDagNode();
// And now take the variable being assigned to out of the current live list
dag.RemoveDagNodeForVariable(XNode.VariableBeingAssigned);
// Also remove all DAG sub expressions using the variable - since the new value
// makes them redundant
dag.RemoveDagExpressionsUsingVariable(XNode.VariableBeingAssigned);
// Then make a new variable in the live list in the dag, so that references to
// the variable later on will see the new dag node instead.
dag.AddDagNodeForVariable(XNode.VariableBeingAssigned);
}
else if (XNode.IsVariable) {
// A variable node has no child nodes, so you can just proces it directly
DagNode n = dag.GetDagNodeForVariable(XNode.Variable));
if (n) XNode.DagNode = n;
else {
XNode.DagNode = dag.CreateDagNodeForVariable(XNode.Variable);
}
return XNode.DagNode;
}
else if (XNode.IsOperator) {
DagNode leftDagNode = XNode.LeftXNode.GetDagNode(dag);
DagNode rightDagNode = XNode.RightXNode.GetDagNode(dag);
// Here you can observe how supplying the operator id and both operands that it
// looks in the Dags live list to check if this expression is already there. If
// it is then it returns it and that is how a common sub-expression is formed.
// This is called an internal node.
XNode.DagNode =
dag.GetOrCreateDagNodeForOperator(XNode.Operator,leftDagNode,RightDagNode) );
return XNode.DagNode;
}
}
それはそれを見る一つの方法です。ツリーの基本的なウォークと、Dagノードを追加および参照するだけです。DAGのルートは、たとえばツリーのルートが返すDagNodeです。
明らかに、サンプルの手順は、より小さな部分に分割したり、仮想関数を持つサブクラスとして作成したりできます。
Dagの並べ替えについては、各DagNodeを左から右に移動します。言い換えると、DagNodeの左側の端に続いて、右側の端に続きます。番号は逆に割り当てられます。つまり、子のないDagNodeに到達したら、そのノードに現在の並べ替え番号を割り当て、並べ替え番号をインクリメントします。これにより、再帰が解かれ、番号が昇順に割り当てられます。
この例では、子が0個または2個のノードを持つツリーのみを処理します。明らかに、一部のツリーには3つ以上の子を持つノードがあるため、ロジックは同じです。左と右を計算する代わりに、左から右などに計算します...
// Most basic DAG topological ordering example.
void DagNode::OrderDAG(int* counter) {
if (this->AlreadyCounted) return;
// Count from left to right
for x = 0 to this->Children.Count-1
this->Children[x].OrderDag(counter)
// And finally number the DAG Node here after all
// the children have been numbered
this->DAGOrder = *counter;
// Increment the counter so the caller gets a higher number
*counter = *counter + 1;
// Mark as processed so will count again
this->AlreadyCounted = TRUE;
}
名前は、その定義について知っておく必要のあることのほとんどを示しています。これは、すべてのエッジが一方向にのみ流れるグラフであり、エッジをクロールすると、パスは左に戻った頂点に戻ることはありません。
すべての使用法について話すことはできませんが(Wikipediaが役立ちます)、DAGは私にとって、リソース間の依存関係を決定するときに非常に役立ちます。たとえば、私のゲームエンジンは、読み込まれたすべてのリソース(マテリアル、テクスチャ、シェーダー、プレーンテキスト、解析されたjsonなど)を単一のDAGとして表します。例:
マテリアルはN GLプログラムであり、それぞれに2つのシェーダーが必要で、各シェーダーにはプレーンテキストシェーダーソースが必要です。これらのリソースをDAGとして表すことにより、既存のリソースのグラフを簡単にクエリして、重複した負荷を回避できます。複数のマテリアルで同じソースコードの頂点シェーダーを使用するとします。既存のリソースに新しいエッジを確立できるだけの場合は、ソースをリロードしてすべての用途でシェーダーを再コンパイルするのは無駄です。このように、グラフを使用してリソースに依存しているものがあるかどうかを判断し、依存していない場合は削除してメモリを解放することもできます。実際、これはほとんど自動的に行われます。
拡張により、DAGはデータ処理パイプラインを表現するのに役立ちます。非周期的性質とは、同じ頂点に再遭遇することなく、頂点からエッジまでポインターをたどることができるコンテキスト処理コードを安全に記述できることを意味します。VVVV、Max MSP、Autodesk Mayaのノードベースのインターフェースなどのビジュアルプログラミング言語はすべてDAGに依存しています。
有向非巡回グラフは、...非有向グラフを表現したい場合に便利です!正規の例は家系図または系図です。