#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; } double 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 DAGGraph::graph_layer_nodes_sort(int layer_index, const QList>& nodes) { QList> 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()) { // 计算当前层次所有节点排序 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 prev_sorts; auto upstream_list = target_node->getUpstreamNodes(); std::transform(upstream_list.begin(), upstream_list.end(), std::back_inserter(prev_sorts), [](std::shared_ptr 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(target_node)->layerNode()->bindPoint().name().contains(u8"小师姐叛逃")) { qDebug() << ""; } } } // 提取当前层次节点排序值 QList sort_values; std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), std::back_inserter(sort_values), [](std::shared_ptr 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 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); } } } this->above_nodes_sort(layer_index, nodes); this->graph_layer_nodes_sort(layer_index + 1, nodes); } } void dags::DAGGraph::above_nodes_sort(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(); }); 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()); node->setSortNumber(sort_idx - temp_anchor.second); } } void dags::DAGGraph::graph_adjust_after_layout(const QList>& total_nodes) { int curr_layer = 0; while (layer_adjust_after_layout(curr_layer++, total_nodes)) { this->above_nodes_sort(curr_layer, total_nodes); } } bool dags::DAGGraph::layer_adjust_after_layout(int curr_layer, const QList>& total_nodes) { QList> nodes_within_current_layer; std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(nodes_within_current_layer), [&](std::shared_ptr ins) { return ins->layerNumber() == curr_layer; }); if (!nodes_within_current_layer.size()) return false; for (auto node : nodes_within_current_layer) { this->node_adjust_after_layout(node, total_nodes); } return true; } void dags::DAGGraph::node_adjust_after_layout(std::shared_ptr curr_node, const QList>& total_nodes) { auto next_data = curr_node->headsNode(); auto upstream_nodes = curr_node->getUpstreamNodes(); } void dags::DAGGraph::graphLayout() { 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_layer_nodes_sort(0, tidy_nodes); this->node_with_layout = tidy_nodes; }