340 lines
9.6 KiB
C++
340 lines
9.6 KiB
C++
#include "dag_layout.h"
|
||
using namespace dags;
|
||
using namespace graph_data;
|
||
|
||
DAGLayerHelper::DAGLayerHelper(const Node& bind)
|
||
: bind_node(bind) {
|
||
}
|
||
|
||
Node DAGLayerHelper::bindPoint() const {
|
||
return this->bind_node;
|
||
}
|
||
|
||
int& dags::DAGLayerHelper::inputCount() {
|
||
return this->input_count;
|
||
}
|
||
|
||
int dags::DAGLayerHelper::layerValue() const {
|
||
return this->layer_v;
|
||
}
|
||
|
||
void dags::DAGLayerHelper::setLayerValue(int v) {
|
||
this->layer_v = v;
|
||
}
|
||
|
||
void DAGLayerHelper::nextAppend(std::shared_ptr<DAGLayerHelper> inst) {
|
||
if (this->next_points.contains(inst))
|
||
return;
|
||
this->next_points.append(inst);
|
||
inst->input_count++;
|
||
}
|
||
|
||
QList<std::shared_ptr<DAGLayerHelper>> DAGLayerHelper::nextNodes() const {
|
||
return this->next_points;
|
||
}
|
||
|
||
DAGOrderHelper::DAGOrderHelper(std::shared_ptr<DAGLayerHelper> bind) : layer_bind(bind) {
|
||
this->layer_number = bind->layerValue();
|
||
}
|
||
|
||
DAGOrderHelper::DAGOrderHelper(std::shared_ptr<DAGLayerHelper> f, std::shared_ptr<DAGLayerHelper> t)
|
||
: relate_bind(f), towards_to(t) {
|
||
}
|
||
|
||
bool DAGOrderHelper::isFakeNode() const {
|
||
return !this->layer_bind;
|
||
}
|
||
|
||
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::layerNode() const {
|
||
return this->layer_bind;
|
||
}
|
||
|
||
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::relateNode() const {
|
||
return this->relate_bind;
|
||
}
|
||
|
||
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::towardsNode() const {
|
||
return this->towards_to;
|
||
}
|
||
|
||
int dags::DAGOrderHelper::layerNumber() const {
|
||
return this->layer_number;
|
||
}
|
||
|
||
void dags::DAGOrderHelper::setLayerNumber(int v) {
|
||
this->layer_number = v;
|
||
}
|
||
|
||
double dags::DAGOrderHelper::sortNumber() const {
|
||
return this->sort_number;
|
||
}
|
||
|
||
void dags::DAGOrderHelper::setSortNumber(double v) {
|
||
this->sort_number = v;
|
||
}
|
||
|
||
QList<std::shared_ptr<DAGOrderHelper>> DAGOrderHelper::getUpstreamNodes() const {
|
||
return this->__prev_layer_nodes;
|
||
}
|
||
|
||
void DAGOrderHelper::appendUpstreamNode(std::shared_ptr<DAGOrderHelper> inst) {
|
||
this->__prev_layer_nodes.append(inst);
|
||
}
|
||
|
||
void DAGGraph::rebuildFromEdges(const QList<Arrow>& arrow_list) {
|
||
for (auto& arr : arrow_list) {
|
||
auto start = arr.startPoint();
|
||
std::shared_ptr<DAGLayerHelper> start_helper;
|
||
if (this->graph_inst.contains(start.name())) {
|
||
start_helper = this->graph_inst[start.name()];
|
||
}
|
||
else {
|
||
start_helper = std::make_shared<DAGLayerHelper>(start);
|
||
this->graph_inst[start.name()] = start_helper;
|
||
}
|
||
|
||
auto end = arr.endPoint();
|
||
std::shared_ptr< DAGLayerHelper> end_helper;
|
||
if (this->graph_inst.contains(end.name())) {
|
||
end_helper = this->graph_inst[end.name()];
|
||
}
|
||
else {
|
||
end_helper = std::make_shared<DAGLayerHelper>(end);
|
||
this->graph_inst[end.name()] = end_helper;
|
||
}
|
||
|
||
start_helper->nextAppend(end_helper);
|
||
}
|
||
}
|
||
|
||
QList<std::shared_ptr<DAGOrderHelper>> dags::DAGGraph::nodeWithLayout() const {
|
||
return this->node_with_layout;
|
||
}
|
||
|
||
int dags::DAGGraph::maxLayerCount() const {
|
||
return this->max_layer_count;
|
||
}
|
||
|
||
std::shared_ptr<DAGLayerHelper> DAGGraph::spawns_peak(QList<std::shared_ptr<DAGLayerHelper>>& ref_set) {
|
||
for (auto inst : ref_set) {
|
||
if (!inst->inputCount()) {
|
||
for (auto it_nxt : inst->nextNodes()) {
|
||
it_nxt->inputCount()--;
|
||
if (!ref_set.contains(it_nxt))
|
||
ref_set << it_nxt;
|
||
}
|
||
|
||
ref_set.removeAll(inst);
|
||
this->graph_inst.remove(inst->bindPoint().name());
|
||
return inst;
|
||
}
|
||
}
|
||
|
||
for (auto inst : this->graph_inst.values()) {
|
||
if (!inst->inputCount()) {
|
||
if (ref_set.contains(inst))
|
||
ref_set.removeAll(inst);
|
||
|
||
for (auto it_nxt : inst->nextNodes()) {
|
||
it_nxt->inputCount()--;
|
||
if (!ref_set.contains(it_nxt))
|
||
ref_set << it_nxt;
|
||
}
|
||
|
||
this->graph_inst.remove(inst->bindPoint().name());
|
||
return inst;
|
||
}
|
||
}
|
||
|
||
if (this->graph_inst.size()) {
|
||
throw "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>з<EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD>λ<EFBFBD>·<EFBFBD><EFBFBD>";
|
||
}
|
||
|
||
return std::shared_ptr<DAGLayerHelper>();
|
||
}
|
||
|
||
void DAGGraph::graph_recovery(QList<std::shared_ptr<DAGLayerHelper>> sort_seqs) {
|
||
for (auto it : sort_seqs) {
|
||
it->inputCount() = 0;
|
||
}
|
||
|
||
for (auto it : sort_seqs) {
|
||
for (auto nxt : it->nextNodes()) {
|
||
nxt->inputCount()++;
|
||
}
|
||
}
|
||
|
||
this->graph_inst.clear();
|
||
for (auto it : sort_seqs) {
|
||
this->graph_inst[it->bindPoint().name()] = it;
|
||
}
|
||
}
|
||
|
||
int DAGGraph::node_layering(std::shared_ptr<DAGLayerHelper> inst, int layer_current) {
|
||
auto max_remains = layer_current;
|
||
if (!layer_current || inst->layerValue() < layer_current) {
|
||
inst->setLayerValue(layer_current);
|
||
|
||
for (auto fork : inst->nextNodes()) {
|
||
max_remains = std::max(this->node_layering(fork, inst->layerValue() + 1), max_remains);
|
||
}
|
||
}
|
||
|
||
return max_remains + 1;
|
||
}
|
||
|
||
int DAGGraph::node_layering_adj(std::shared_ptr<DAGLayerHelper> inst) {
|
||
if (inst->inputCount() > 1)
|
||
return inst->layerValue() - 1;
|
||
|
||
if (!inst->nextNodes().size())
|
||
return inst->layerValue() - 1;
|
||
|
||
auto layer_number = INT_MAX;
|
||
for (auto cinst : inst->nextNodes()) {
|
||
layer_number = std::min(layer_number, this->node_layering_adj(cinst));
|
||
}
|
||
|
||
inst->setLayerValue(layer_number);
|
||
return inst->layerValue() - 1;
|
||
}
|
||
|
||
QList<std::shared_ptr<DAGOrderHelper>> DAGGraph::tidy_graph_nodes() {
|
||
QHash<QString, std::shared_ptr<DAGOrderHelper>> nodes_temp;
|
||
for (auto node : this->graph_inst.values()) {
|
||
nodes_temp[node->bindPoint().name()] = std::make_shared<DAGOrderHelper>(node);
|
||
}
|
||
|
||
QList<std::shared_ptr<DAGOrderHelper>> temp_array(nodes_temp.values());
|
||
for (auto node : this->graph_inst.values()) {
|
||
for (auto next : node->nextNodes()) {
|
||
auto node_links = QList<std::shared_ptr<DAGOrderHelper>>{
|
||
nodes_temp[node->bindPoint().name()]
|
||
};
|
||
for (auto layer_index = node->layerValue() + 1; layer_index < next->layerValue(); ++layer_index) {
|
||
node_links.append(std::make_shared<DAGOrderHelper>(node, next));
|
||
node_links.last()->setLayerNumber(layer_index);
|
||
}
|
||
node_links.append(nodes_temp[next->bindPoint().name()]);
|
||
for (auto idx = 1; idx < node_links.size(); ++idx) {
|
||
auto start_point = node_links[idx - 1];
|
||
auto end_point = node_links[idx];
|
||
end_point->appendUpstreamNode(start_point);
|
||
}
|
||
temp_array.append(node_links.mid(1, node_links.size() - 2));
|
||
}
|
||
}
|
||
return temp_array;
|
||
}
|
||
|
||
#include <QDebug>
|
||
void DAGGraph::graph_layer_nodes_sort(int layer_index, QList<std::shared_ptr<DAGOrderHelper>> nodes) {
|
||
QList<std::shared_ptr<DAGOrderHelper>> nodes_within_current_layer;
|
||
for (auto n : nodes)
|
||
if (n->layerNumber() == layer_index) {
|
||
nodes_within_current_layer.append(n);
|
||
}
|
||
|
||
if (nodes_within_current_layer.size()) {
|
||
// <20><><EFBFBD>㵱ǰ<E3B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
||
if (!layer_index) {
|
||
for (auto idx = 0; idx < nodes_within_current_layer.size(); ++idx) {
|
||
nodes_within_current_layer[idx]->setSortNumber(idx + 1);
|
||
}
|
||
}
|
||
else if (layer_index > 0) {
|
||
for (auto target_node : nodes_within_current_layer) {
|
||
QList<double> prev_sorts;
|
||
auto upstream_list = target_node->getUpstreamNodes();
|
||
std::transform(upstream_list.begin(), upstream_list.end(),
|
||
std::back_inserter(prev_sorts), [](std::shared_ptr<DAGOrderHelper> inst) {
|
||
return inst->sortNumber();
|
||
});
|
||
|
||
if (prev_sorts.size()) {
|
||
auto target_sum = std::accumulate(prev_sorts.begin(), prev_sorts.end(), 0.0);
|
||
target_node->setSortNumber(target_sum / prev_sorts.size());
|
||
if (!target_node->isFakeNode() && std::shared_ptr<DAGOrderHelper>(target_node)->layerNode()->bindPoint().name().contains(u8"Сʦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")) {
|
||
qDebug() << "";
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD>νڵ<CEBD><DAB5><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
QList<double> sort_values;
|
||
std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(),
|
||
std::back_inserter(sort_values), [](std::shared_ptr<DAGOrderHelper> n) { return n->sortNumber(); });
|
||
sort_values = sort_values.toSet().toList();
|
||
|
||
for (auto& sort_v : sort_values) {
|
||
decltype(nodes_within_current_layer) pick_items;
|
||
std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(),
|
||
std::back_inserter(pick_items), [=](std::shared_ptr<DAGOrderHelper> ins) { return ins->sortNumber() == sort_v; });
|
||
|
||
for (int idx = 0; idx < pick_items.size(); ++idx) {
|
||
auto item = pick_items[idx];
|
||
item->setSortNumber(item->sortNumber() + 0.000000001 * idx);
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪<EFBFBD>ڵ<EFBFBD>
|
||
QList<std::shared_ptr<DAGOrderHelper>> sorting_nodes;
|
||
std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(sorting_nodes),
|
||
[&](std::shared_ptr<DAGOrderHelper> n) { return n->layerNumber() <= layer_index; });
|
||
|
||
// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
QList<double> sort_values;
|
||
std::transform(sorting_nodes.begin(), sorting_nodes.end(), std::back_inserter(sort_values),
|
||
[](std::shared_ptr<DAGOrderHelper> n)->double { return n->sortNumber(); });
|
||
sort_values = sort_values.toSet().toList();
|
||
std::sort(sort_values.begin(), sort_values.end());
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
auto temp_anchor = std::make_pair<double, int>(DBL_MAX, -1);
|
||
for (int nidx = 0; nidx < sort_values.size(); ++nidx) {
|
||
auto value_span = std::abs(sort_values[nidx]);
|
||
if (value_span <= temp_anchor.first)
|
||
temp_anchor = std::make_pair(value_span, nidx);
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>
|
||
for (int sorting_idx = 0; sorting_idx < sorting_nodes.size(); ++sorting_idx) {
|
||
auto node = sorting_nodes[sorting_idx];
|
||
auto sort_idx = sort_values.indexOf(node->sortNumber());
|
||
node->setSortNumber(sort_idx - temp_anchor.second);
|
||
}
|
||
|
||
this->graph_layer_nodes_sort(layer_index + 1, nodes);
|
||
}
|
||
}
|
||
|
||
void dags::DAGGraph::graphLayout() {
|
||
QList<std::shared_ptr<DAGLayerHelper>> sort_seqs;
|
||
QList<std::shared_ptr<DAGLayerHelper>> refs;
|
||
while (1) {
|
||
auto peaks = this->spawns_peak(refs);
|
||
if (!peaks)
|
||
break;
|
||
|
||
sort_seqs.append(peaks);
|
||
}
|
||
this->graph_recovery(sort_seqs);
|
||
for (auto item : sort_seqs) {
|
||
if (!item->inputCount()) {
|
||
this->max_layer_count = std::max(this->max_layer_count, this->node_layering(item, 0));
|
||
}
|
||
}
|
||
for (auto item : sort_seqs) {
|
||
if (!item->inputCount()) {
|
||
this->node_layering_adj(item);
|
||
}
|
||
}
|
||
|
||
auto tidy_nodes = this->tidy_graph_nodes();
|
||
this->graph_layer_nodes_sort(0, tidy_nodes);
|
||
this->node_with_layout = tidy_nodes;
|
||
}
|
||
|
||
|