#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 inst) { if (this->next_points.contains(inst)) return; this->next_points.append(inst); inst->input_count++; } QList> DAGLayerHelper::nextNodes() const { return this->next_points; } DAGOrderHelper::DAGOrderHelper(std::shared_ptr bind) : layer_bind(bind) { this->layer_number = bind->layerValue(); } DAGOrderHelper::DAGOrderHelper(std::shared_ptr f, std::shared_ptr t) : relate_bind(f), towards_to(t) { } bool DAGOrderHelper::isFakeNode() const { return !this->layer_bind; } std::shared_ptr dags::DAGOrderHelper::layerNode() const { return this->layer_bind; } std::shared_ptr dags::DAGOrderHelper::tailsNode() const { return this->relate_bind; } std::shared_ptr dags::DAGOrderHelper::headsNode() const { return this->towards_to; } int dags::DAGOrderHelper::layerNumber() const { return this->layer_number; } void dags::DAGOrderHelper::setLayerNumber(int v) { this->layer_number = v; } QVariant dags::DAGOrderHelper::sortNumber() const { return this->sort_number; } void dags::DAGOrderHelper::setSortNumber(double v) { this->sort_number = v; } QList> DAGOrderHelper::getUpstreamNodes() const { return this->__prev_layer_nodes; } void DAGOrderHelper::appendUpstreamNode(std::shared_ptr inst) { this->__prev_layer_nodes.append(inst); } void DAGGraph::rebuildFromEdges(const QList& arrow_list) { for (auto& arr : arrow_list) { auto start = arr.startPoint(); std::shared_ptr start_helper; if (this->graph_inst.contains(start.name())) { start_helper = this->graph_inst[start.name()]; } else { start_helper = std::make_shared(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(end); this->graph_inst[end.name()] = end_helper; } start_helper->nextAppend(end_helper); } } QList> dags::DAGGraph::nodeWithLayout() const { return this->node_with_layout; } int dags::DAGGraph::maxLayerCount() const { return this->max_layer_count; } std::shared_ptr DAGGraph::spawns_peak(QList>& 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 "在有向无环图中发现环形回路。"; } return std::shared_ptr(); } void DAGGraph::graph_recovery(const QList>& 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(const std::shared_ptr& 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 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> DAGGraph::tidy_graph_nodes() { QHash> nodes_temp; for (auto node : this->graph_inst.values()) { nodes_temp[node->bindPoint().name()] = std::make_shared(node); } QList> temp_array(nodes_temp.values()); for (auto node : this->graph_inst.values()) { for (auto next : node->nextNodes()) { auto node_links = QList>{ nodes_temp[node->bindPoint().name()] }; for (auto layer_index = node->layerValue() + 1; layer_index < next->layerValue(); ++layer_index) { node_links.append(std::make_shared(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 void dags::DAGGraph::graph_layout_layers_forward(const QList>& nodes) { for (auto layer_index = 0; layer_index < maxLayerCount(); ++layer_index) { this->nodes_sort_forward_within_layer(layer_index, nodes); this->nodes_sort_with_above(layer_index, nodes); } } void DAGGraph::nodes_sort_forward_within_layer(int layer_index, const QList>& nodes) { QList> nodes_within_current_layer; std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(nodes_within_current_layer), [=](std::shared_ptr ins) { return ins->layerNumber() == layer_index; }); if (nodes_within_current_layer.size()) { // 计算当前层次所有节点排序 if (!layer_index) { for (auto idx = 0; idx < nodes_within_current_layer.size(); ++idx) { auto target_node = nodes_within_current_layer[idx]; if (target_node->sortNumber().isNull()) target_node->setSortNumber(idx + 1); } } else if (layer_index > 0) { double min_sortv = DBL_MAX; for (auto target_node : nodes_within_current_layer) { auto upstream_list = target_node->getUpstreamNodes(); if (upstream_list.size()) { QList sort_values; std::transform(upstream_list.begin(), upstream_list.end(), std::back_inserter(sort_values), [](std::shared_ptr ins) { return ins->sortNumber().toDouble(); }); auto vals_sum = std::accumulate(sort_values.begin(), sort_values.end(), 0.0); target_node->setSortNumber(vals_sum / sort_values.size()); min_sortv = std::min(target_node->sortNumber().toDouble(), min_sortv); } } QList> nodes_hangout; std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), std::back_inserter(nodes_hangout), [](std::shared_ptr ins) { return ins->sortNumber().isNull(); }); if (nodes_hangout.size()) { auto vspan = 1.0 / (nodes_hangout.size() + 1); for (int idx = 0; idx < nodes_hangout.size(); ++idx) { nodes_hangout[idx]->setSortNumber(min_sortv - (idx + 1) * vspan); } } std::sort(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); // 提取当前层次节点排序值 this->current_nodelist_filling_indi(nodes_within_current_layer); } } } bool dags::DAGGraph::current_nodelist_filling_indi(const QList>& nodes_within_current_layer) { // 提取节点划分档次 QList ordered_values; std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), std::back_inserter(ordered_values), [=](std::shared_ptr ins) { return ins->sortNumber().toInt(); }); ordered_values = ordered_values.toSet().toList(); std::sort(ordered_values.begin(), ordered_values.end()); //if (ordered_values.size() == nodes_within_current_layer.size()) // return false; if (!ordered_values.size()) return false; // 填缝 ordered_values << ordered_values.last() + 1; for (auto idx = 1; idx < ordered_values.size(); ++idx) { auto prev_sortv = ordered_values[idx - 1]; auto curr_sortv = ordered_values[idx]; QList> pick_ups; std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), std::back_inserter(pick_ups), [=](std::shared_ptr ins) { return ins->sortNumber() >= prev_sortv && ins->sortNumber() < curr_sortv; }); for (int idx = 0; idx < std::min(curr_sortv - prev_sortv, pick_ups.size()); idx++) { auto target_node = pick_ups[idx]; target_node->setSortNumber(prev_sortv + idx); } if (curr_sortv - prev_sortv < pick_ups.size()) { auto npicks = pick_ups.mid(curr_sortv - prev_sortv); auto inc_span = 1.0 / (npicks.size() + 4); for (auto idx = 0; idx < npicks.size(); ++idx) { auto nsortv = curr_sortv - 1 + (idx + 1) * inc_span; npicks[idx]->setSortNumber(nsortv); } } } return true; } void dags::DAGGraph::nodes_sort_with_above(int layer_index, const QList>& nodes) { // 提取所有已知节点 QList> sorting_nodes; std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(sorting_nodes), [&](std::shared_ptr n) { return n->layerNumber() <= layer_index; }); // 排序值提取与重排 QList sort_values; std::transform(sorting_nodes.begin(), sorting_nodes.end(), std::back_inserter(sort_values), [](std::shared_ptr n)->double { return n->sortNumber().toDouble(); }); sort_values = sort_values.toSet().toList(); std::sort(sort_values.begin(), sort_values.end()); // 检索排序中轴 auto temp_anchor = std::make_pair(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); } // 排序值重整 for (int sorting_idx = 0; sorting_idx < sorting_nodes.size(); ++sorting_idx) { auto node = sorting_nodes[sorting_idx]; auto node_sortv = node->sortNumber().toDouble(); auto sort_idx = sort_values.indexOf(node_sortv); node->setSortNumber(sort_idx - temp_anchor.second); } } void dags::DAGGraph::graph_adjust_layers_backward(const QList>& total_nodes) { auto layer_index = this->maxLayerCount() - 1; while (layer_index > -1) { auto nlist = this->layer_adjust_via_next_sibling(layer_index, total_nodes); if (this->current_nodelist_filling_indi(nlist)) this->nodes_sort_with_belows(layer_index, total_nodes); layer_index--; }; } QList> dags::DAGGraph::layer_adjust_via_next_sibling(int curr_layer, const QList>& total_nodes) { QList> curr_layer_nodes; std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(curr_layer_nodes), [&](std::shared_ptr inst) { return inst->layerNumber() == curr_layer; }); for (auto node : curr_layer_nodes) { this->node_adjust_via_next_sibling(node, total_nodes); } std::sort(curr_layer_nodes.begin(), curr_layer_nodes.end(), [](std::shared_ptra, std::shared_ptr b)->bool { auto prevs_a = a->getUpstreamNodes(); auto prevs_b = b->getUpstreamNodes(); if (!prevs_a.size() && !prevs_b.size()) return a > b; if (!prevs_a.size()) return true; if (!prevs_b.size()) return false; auto upnode_a = std::min_element(prevs_a.begin(), prevs_a.end(), [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); auto upnode_b = std::min_element(prevs_b.begin(), prevs_b.end(), [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); return (*upnode_a)->sortNumber() < (*upnode_b)->sortNumber(); }); return curr_layer_nodes; } void dags::DAGGraph::node_adjust_via_next_sibling(std::shared_ptr curr_node, const QList>& total_nodes) { // 计算下游调整参考节点 QList> next_layer_nodes; std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(next_layer_nodes), [&](std::shared_ptr inst) { if (inst->layerNumber() == curr_node->layerNumber() + 1) { if (curr_node->isFakeNode()) { if (inst->isFakeNode()) { return curr_node->tailsNode() == inst->tailsNode() && curr_node->headsNode() == inst->headsNode(); } return curr_node->headsNode() == inst->layerNode(); } else { if (inst->isFakeNode()) { return curr_node->layerNode() == inst->tailsNode(); } else { auto next_vnodes = curr_node->layerNode()->nextNodes(); return next_vnodes.contains(inst->layerNode()); } } } return false; }); std::sort(next_layer_nodes.begin(), next_layer_nodes.end(), [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); if (next_layer_nodes.size()) { curr_node->setSortNumber(next_layer_nodes.first()->sortNumber().toDouble()); } } void dags::DAGGraph::nodes_sort_with_belows(int curr_layer, const QList>& total_nodes) { // 提取所有已知节点 QList> sorting_nodes; std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(sorting_nodes), [=](std::shared_ptr ins) { return ins->layerNumber() >= curr_layer; }); // 排序值提取与重排 QList sort_values; std::transform(sorting_nodes.begin(), sorting_nodes.end(), std::back_inserter(sort_values), [](std::shared_ptr n)->double { return n->sortNumber().toDouble(); }); sort_values = sort_values.toSet().toList(); std::sort(sort_values.begin(), sort_values.end()); // 检索排序中轴 auto temp_anchor = std::make_pair(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); } // 排序值重整 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().toDouble()); node->setSortNumber(sort_idx - temp_anchor.second); } } void dags::DAGGraph::primitiveGraphLayout() { QList> sort_seqs; QList> 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_layout_layers_forward(tidy_nodes); this->node_with_layout = tidy_nodes; } void dags::DAGGraph::forwardsLayoutImpls() { this->graph_layout_layers_forward(this->node_with_layout); } void dags::DAGGraph::backwardsLayoutImpls() { this->graph_adjust_layers_backward(this->node_with_layout); } void dags::DAGGraph::adjustLayoutImpls() { }