今、私はForce Directed Graphの実装をスピードアップしようとしています。これまで私は、計算数を減らすためにオクトリーを使用しているBarnes-Hutアルゴリズムを実装しました。私はそれを何度も試してみましたが、力に関連する計算の数は実際には大幅に減少しました。以下は、Barns-Hut(青い線)を使わないノードの数に対する計算のプロットです。 今はもっと速くなければなりませんが、真実はスピード(時間)アップグレードはわずか数パーセントです。オクトリーの実装のスピードの懸念
これは、ツリーの作成とツリー配置の要素が原因と考えられます。要素は絶えず動いているので、何らかの停止条件に達するまで、各ループを再作成する必要があります。しかし、木をつくるのに多くの時間を費やすと、そこでは力の計算が増えた時があります。それは少なくとも私の考えです。私はここでやっていることは、グラフ内のすべての私の要素を通過し、ツリーのルートに追加され
void AddTreeElements(Octree* tree, glm::vec3* boundries, Graph& graph)
{
for(auto& node:graph.NodeVector())
{
node.parent_group = nullptr;
if(node.pos[0] < boundries[1][0] && node.pos[0] > boundries[0][0] &&
node.pos[1] > boundries[4][1] && node.pos[1] < boundries[1][1] &&
node.pos[2] < boundries[0][2] && node.pos[2] > boundries[3][2])
{
tree->AddObject(&node.second);
continue;
}
if(node.pos[0] < boundries[0][0])
{
boundries[0][0] = node.pos[0]-1.0f;
boundries[3][0] = node.pos[0]-1.0f;
boundries[4][0] = node.pos[0]-1.0f;
boundries[7][0] = node.pos[0]-1.0f;
}
else if(node.pos[0] > boundries[1][0])
{
boundries[1][0] = node.pos[0]+1.0f;
boundries[2][0] = node.pos[0]+1.0f;
boundries[5][0] = node.pos[0]+1.0f;
boundries[6][0] = node.pos[0]+1.0f;
}
if(node.pos[1] < boundries[4][1])
{
boundries[4][1] = node.pos[1]-1.0f;
boundries[5][1] = node.pos[1]-1.0f;
boundries[6][1] = node.pos[1]-1.0f;
boundries[7][1] = node.pos[1]-1.0f;
}
else if(node.pos[1] > boundries[0][1])
{
boundries[0][1] = node.pos[1]+1.0f;
boundries[1][1] = node.pos[1]+1.0f;
boundries[2][1] = node.pos[1]+1.0f;
boundries[3][1] = node.pos[1]+1.0f;
}
if(node.pos[2] < boundries[3][2])
{
boundries[2][2] = node.pos[2]-1.0f;
boundries[3][2] = node.pos[2]-1.0f;
boundries[6][2] = node.pos[2]-1.0f;
boundries[7][2] = node.pos[2]-1.0f;
}
else if(node.pos[2] > boundries[0][2])
{
boundries[0][2] = node.pos[2]+1.0f;
boundries[1][2] = node.pos[2]+1.0f;
boundries[4][2] = node.pos[2]+1.0f;
boundries[5][2] = node.pos[2]+1.0f;
}
}
}
:私は私のメインのファイルループ内の要素を追加してい方法です。また、私は、次のループのために私のオクトリーボーダーを表すボックスを拡張しているので、すべてのノードが内部に収まるでしょう。次のような構造の更新をオクトリすることが重要
フィールドは、次のとおりです。
Octree* trees[2][2][2];
glm::vec3 vBoundriesBox[8];
bool leaf;
float combined_weight = 0;
std::vector<Element*> objects;
および更新を担当するコードの一部:
#define MAX_LEVELS 5
void Octree::AddObject(Element* object)
{
this->objects.push_back(object);
}
void Octree::Update()
{
if(this->objects.size()<=1 || level > MAX_LEVELS)
{
for(Element* Element:this->objects)
{
Element->parent_group = this;
}
return;
}
if(leaf)
{
GenerateChildren();
leaf = false;
}
while (!this->objects.empty())
{
Element* obj = this->objects.back();
this->objects.pop_back();
if(contains(trees[0][0][0],obj))
{
trees[0][0][0]->AddObject(obj);
trees[0][0][0]->combined_weight += obj->weight;
} else if(contains(trees[0][0][1],obj))
{
trees[0][0][1]->AddObject(obj);
trees[0][0][1]->combined_weight += obj->weight;
} else if(contains(trees[0][1][0],obj))
{
trees[0][1][0]->AddObject(obj);
trees[0][1][0]->combined_weight += obj->weight;
} else if(contains(trees[0][1][1],obj))
{
trees[0][1][1]->AddObject(obj);
trees[0][1][1]->combined_weight += obj->weight;
} else if(contains(trees[1][0][0],obj))
{
trees[1][0][0]->AddObject(obj);
trees[1][0][0]->combined_weight += obj->weight;
} else if(contains(trees[1][0][1],obj))
{
trees[1][0][1]->AddObject(obj);
trees[1][0][1]->combined_weight += obj->weight;
} else if(contains(trees[1][1][0],obj))
{
trees[1][1][0]->AddObject(obj);
trees[1][1][0]->combined_weight += obj->weight;
} else if(contains(trees[1][1][1],obj))
{
trees[1][1][1]->AddObject(obj);
trees[1][1][1]->combined_weight += obj->weight;
}
}
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
trees[i][j][k]->Update();
}
}
}
}
bool Octree::contains(Octree* child, Element* object)
{
if(object->pos[0] >= child->vBoundriesBox[0][0] && object->pos[0] <= child->vBoundriesBox[1][0] &&
object->pos[1] >= child->vBoundriesBox[4][1] && object->pos[1] <= child->vBoundriesBox[0][1] &&
object->pos[2] >= child->vBoundriesBox[3][2] && object->pos[2] <= child->vBoundriesBox[0][2])
return true;
return false;
}
私は私にはない木の要素を移動するためにポインタを使用していますのでオブジェクトの作成/破壊がここで問題になると思う。
Element* obj = this->objects.back();
this->objects.pop_back();
if(contains(trees[0][0][0],obj))
私はどのように私がそれを楽しむことができるか、それをスピードアップすることはできませんが、スピードに影響を及ぼす可能性があります。誰かがここで何ができるのですか?
編集:私はいくつかのナプキンの数学をやったと私は大きな速度低下を引き起こしている可能性がありますもう一つの場所があるとし
。私の場合には同じである
number_of_elements * number_of_childern * number_of_faces * MAX_LEVELS
:Update
方法でチェックBoundriesは多くのことをやって私が計算すると、これによる追加の複雑さは、最悪のシナリオであるということですように見えますnumber_of_elements * 240になります。
私のアイデアが妥当かどうか誰かが確認できますか?
http://codereview.stackexchange.com/ – Mihai
@ミハイ私はあなたの提案後に投稿しました:http://codereview.stackexchange.com/questions/127693/speed-concerns-of-octree-implementation – sebap123
DrunkCoderが言っていることはおそらく助けになるでしょうが、パフォーマンスの最適化の最初の3つのルール、すなわち測定、測定、測定を覚えておいてください!プラットフォームにサンプリングCPUプロファイラ(Linuxの場合はperf + hotspot、Windowsの場合はVisual Studioプロファイラ、macOSの場合はInstruments)を使用し、そのデータを使用してパフォーマンスの犯人を探します。 – milianw