static Arc best_predecessor_1 (Node node) { Node src, dest; Arc ln, best; dest = node; /* * Find a source node with the largest weight. */ src = 0; best = 0; for (ln = sourceArcs (dest); ln != 0; ln = nextArc (ln)) { Node new_node; new_node = sourceNode (ln); if (src == 0) { src = new_node; best = ln; } else { if (predecessor_node_weight (new_node, dest) > predecessor_node_weight (src, dest)) { src = new_node; best = ln; } } } /* * The selected node must be unvisited, and * has non-zero weight. */ if ((src == 0) || (nodeStatus (src) & VISITED)) return 0; if (nodeWeight (src) == 0.0) return 0; /* * Return the best link. */ return best; }
static Arc best_predecessor_3 (Node node) { Node src, dest; Arc ln, best; dest = node; /* * Find an incoming arc with the highest execution count. */ best = 0; for (ln = sourceArcs (dest); ln != 0; ln = nextArc (ln)) { if (best == 0) { best = ln; } else { if (predecessor_arc_weight (ln) > predecessor_arc_weight (best)) best = ln; } } /* * The best link must have non-zero weight. */ if ((best == 0) || (arcWeight (best) == 0.0)) return 0; src = sourceNode (best); /* * The source node must be un-visited. */ if (nodeStatus (src) & VISITED) return 0; if ((arcWeight (best) / nodeWeight (src)) < min_prob_requirement) return 0; if ((arcWeight (best) / nodeWeight (dest)) < min_prob_requirement) return 0; /* * Return the best link. */ return best; }
/* * Heuristic solution to the trace selection problem. */ static void SelectTraces (FGraph graph) { ST_Entry sorted_list[MAX_GRAPH_SIZE]; int list_length; Node ptr; Arc arc; int n, trace_id; Node ENTRY; Node seed, current, last; struct Ext *extCurrent, *extNext; /* * Compute level information. */ AddExtensionFields (graph); /* * Mark all nodes unvisited. * Also clear all status bits. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { nodeType (ptr) = 0; /* trace id = 0 */ nodeStatus (ptr) = NOT_VISITED; for (arc = sourceArcs (ptr); arc != 0; arc = nextArc (arc)) arcType (arc) = 0; for (arc = destinationArcs (ptr); arc != 0; arc = nextArc (arc)) arcType (arc) = 0; } /* * Sort all nodes according to the node weight. * From the most important node to the least important node. */ list_length = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { sorted_list[list_length].weight = nodeWeight (ptr); sorted_list[list_length].ptr = ptr; sorted_list[list_length].index = list_length; list_length += 1; if (list_length >= MAX_GRAPH_SIZE) Punt ("SelectTrace: graph is too large"); } max_sort (sorted_list, list_length); /* library/sort.c */ #ifdef WEIGHT_BASED /* * Give higher priority to the execution weight. */ ENTRY = graph->root; trace_id = 1; for (n = 0; n < list_length; n++) { /* * Select the highest weight un-visited node. */ seed = sorted_list[n].ptr; if (nodeStatus (seed) & VISITED) /* if visited, try next */ continue; /* highest node */ /* * Start a new trace. * Mark seed visited. */ nodeType (seed) = trace_id++; nodeStatus (seed) |= VISITED; /* * Grow the trace forward. */ current = seed; for (;;) { Arc ln, arc; Node dest; ln = best_successor_of (current); if (ln == 0) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Cannot include ENTRY node. */ dest = destinationNode (ln); if (dest == ENTRY) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Can not include a dominator. */ extCurrent = nodeExt (current); extNext = nodeExt (dest); if ((extCurrent == 0) | (extNext == 0)) { Punt ("corrupted extension field"); } if (Set_in (extCurrent->dominator, extNext->order)) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Mark the link selected. */ arc = FindSrcArc (current, dest, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted source link"); arc = FindDestArc (current, dest, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted destination link"); /* * Add it to the trace. */ nodeType (dest) = nodeType (seed); nodeStatus (dest) |= VISITED; current = dest; } /* * Grow the trace backward. */ current = seed; for (;;) { Arc ln, arc; Node src; /* * Cannot grow from the ENTRY node. */ if (current == ENTRY) { nodeStatus (current) |= TRACE_HEAD; break; } ln = best_predecessor_of (current); if (ln == 0) { nodeStatus (current) |= TRACE_HEAD; break; } src = sourceNode (ln); /* * Can not include a dominee. */ extCurrent = nodeExt (current); extNext = nodeExt (src); if ((extCurrent == 0) | (extNext == 0)) { Punt ("corrupted extension field"); } if (Set_in (extNext->dominator, extCurrent->order)) { nodeStatus (current) |= TRACE_HEAD; break; } /* * Mark the link selected. */ arc = FindSrcArc (src, current, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted source link"); arc = FindDestArc (src, current, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted destination link"); /* * Add it to the trace. */ nodeType (src) = nodeType (seed); nodeStatus (src) |= VISITED; current = src; } } #else /* * Give more attention to the natural flow of the * program. */ ENTRY = graph->root; trace_id = 1; current = ENTRY; /* start from the entry block */ last = 0; for (n = 0; n < list_length; n++) { if (!(nodeStatus (current) & VISITED)) { /* * 1) start from the start node first. */ seed = current; } else { /* * 2) select a fall_thru node if possible. * 3) select the most important node. */ Node best, dest; Arc pc; if (last == 0) Punt ("this should not happen"); best = 0; for (pc = destinationArcs (last); pc != 0; pc = nextArc (pc)) { dest = destinationNode (pc); if (nodeStatus (dest) & VISITED) continue; if (best == 0) { best = dest; } else if (successor_node_weight (last, dest) > successor_node_weight (last, best)) { best = dest; } } if (best == 0) { int k; for (k = 0; k < list_length; k++) { dest = (Node) sorted_list[k].ptr; if (nodeStatus (dest) & VISITED) continue; best = dest; break; } } if (best == 0) { break; } seed = best; } if (nodeStatus (seed) & VISITED) Punt ("incorrect seed selection"); /* * Start a new trace. * Mark seed visited. */ nodeType (seed) = trace_id++; nodeStatus (seed) |= VISITED; /* * Grow the trace forward. */ current = seed; for (;;) { Arc ln, arc; Node dest; ln = best_successor_of (current); if (ln == 0) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Cannot include ENTRY node. */ dest = destinationNode (ln); if (dest == ENTRY) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Can not include a dominator. */ extCurrent = (struct Ext *) nodeExt (current); extNext = (struct Ext *) nodeExt (dest); if ((extCurrent == 0) || (extNext == 0)) { Punt ("corrupted extension field"); } if (Set_in (extCurrent->dominator, extNext->order)) { nodeStatus (current) |= TRACE_TAIL; break; } /* * Mark the link selected. */ arc = FindSrcArc (current, dest, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted source link"); arc = FindDestArc (current, dest, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted destination link"); /* * Add it to the trace. */ nodeType (dest) = nodeType (seed); nodeStatus (dest) |= VISITED; current = dest; } last = current; /* * Grow the trace backward. */ current = seed; for (;;) { Arc ln, arc; Node src; /* * Cannot grow from the ENTRY node. */ if (current == ENTRY) { nodeStatus (current) |= TRACE_HEAD; break; } ln = best_predecessor_of (current); if (ln == 0) { nodeStatus (current) |= TRACE_HEAD; break; } src = sourceNode (ln); /* * Can not include a dominee. */ extCurrent = (struct Ext *) nodeExt (current); extNext = (struct Ext *) nodeExt (src); if ((extCurrent == 0) || (extNext == 0)) { Punt ("corrupted extension field"); } if (Set_in (extNext->dominator, extCurrent->order)) { nodeStatus (current) |= TRACE_HEAD; break; } /* * Mark the link selected. */ arc = FindSrcArc (src, current, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted source link"); arc = FindDestArc (src, current, 0); if (arc != 0) { arcType (arc) = nodeType (seed); } else Punt ("SelectTraces: corrupted destination link"); /* * Add it to the trace. */ nodeType (src) = nodeType (seed); nodeStatus (src) |= VISITED; current = src; } } #endif /* * Make sure that all nodes have been visited. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if (!(nodeStatus (ptr) & VISITED)) Punt ("SelectTraces: failed to select all nodes"); } /* * Detect inner loops. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { Arc ln; if (!(nodeStatus (ptr) & TRACE_TAIL)) continue; for (ln = destinationArcs (ptr); ln != 0; ln = nextArc (ln)) { Node dest; dest = destinationNode (ln); if ((nodeStatus (dest) & TRACE_HEAD) && (nodeType (dest) == nodeType (ptr))) { nodeStatus (dest) |= LOOP_HEAD; break; } } } }
/* * Measure the trace selection result. * Trace selection must have been applied. */ void ReportSelectionResult (FGraph graph, double *matrix) { int i; Node node; Arc arc; if (graph == 0) Punt ("ReportSelectionResult: nil graph"); if (matrix == 0) return; for (i = 0; i <= N_LEAF; i++) matrix[i] = 0.0; /* * Compute the sequential locality. */ for (node = graph->nodes; node != 0; node = nextNode (node)) { Arc ptr; Node next_node; next_node = nextNode (node); if (next_node == 0) /* ignore the last node */ break; for (ptr = destinationArcs (node); ptr != 0; ptr = nextArc (ptr)) { if (destinationNode (ptr) == next_node) { matrix[W_SEQUENTIAL] += arcWeight (ptr); } } } /* * Measure various transition counts. */ for (node = graph->nodes; node != 0; node = nextNode (node)) { for (arc = destinationArcs (node); arc != 0; arc = nextArc (arc)) { Node src, dest; int Sh, St, Dh, Dt; src = sourceNode (arc); dest = destinationNode (arc); Sh = nodeStatus (src) & TRACE_HEAD; St = nodeStatus (src) & TRACE_TAIL; Dh = nodeStatus (dest) & TRACE_HEAD; Dt = nodeStatus (dest) & TRACE_TAIL; if ((arcType (arc) != 0) && (arcType (arc) == nodeType (node))) { /* * In-trace. */ matrix[W_E] += arcWeight (arc); } else if (arcType (arc) != 0) { Punt ("ReportSelectionResult: illegal arc type"); } else { if (St && Dh) { /* terminal to head */ matrix[W_A] += arcWeight (arc); /* detect loop back-edge */ if (nodeType (src) == nodeType (dest)) { matrix[W_BACK_EDGE] += arcWeight (arc); } } else if (St && !Dh) { /* terminal to middle */ matrix[W_B] += arcWeight (arc); } else if (!St && Dh) { /* middle to head */ matrix[W_C] += arcWeight (arc); } else { /* middle to middle */ matrix[W_D] += arcWeight (arc); } } } } #ifdef DEBUG_TRACE2 if (matrix[W_E] > matrix[W_SEQUENTIAL]) { WriteGraph ("zzz.debug", graph); fprintf (stderr, "in-trace = %f\n", matrix[W_E]); fprintf (stderr, "sequential = %f\n", matrix[W_SEQUENTIAL]); Punt ("ReportSelection: incorrect in-trace"); } #endif /* * Measure several graph parameters. */ for (node = graph->nodes; node != 0; node = nextNode (node)) { nodeStatus (node) &= ~VISITED; /* borrow the valid bit */ matrix[N_NODES] += 1.0; matrix[W_NODES] += nodeWeight (node); if (destinationArcs (node) == 0) { matrix[N_LEAF] += 1.0; } if (sourceArcs (node) == 0) { matrix[N_ROOT] += 1.0; } for (arc = destinationArcs (node); arc != 0; arc = nextArc (arc)) { matrix[N_ARCS] += 1.0; matrix[W_ARCS] += arcWeight (arc); } } for (node = graph->nodes; node != 0; node = nextNode (node)) { Node ptr; int trace_id, loop, size; if (nodeStatus (node) & VISITED) continue; trace_id = nodeType (node); loop = 0; size = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if (nodeType (ptr) == trace_id) { nodeStatus (ptr) |= VISITED; size++; loop |= (nodeStatus (node) & LOOP_HEAD); } } matrix[N_TRACE] += 1.0; matrix[L_TRACE] += size; if (loop) { matrix[N_LOOP] += 1.0; matrix[L_LOOP] += size; } } if (matrix[L_TRACE] != matrix[N_NODES]) Punt ("ReportSelectionResult: incorrect accounting"); if (matrix[N_TRACE] != 0.0) matrix[L_TRACE] /= matrix[N_TRACE]; if (matrix[N_LOOP] != 0.0) matrix[L_LOOP] /= matrix[N_LOOP]; }
/* * Places traces in a particular linear order * to maximize sequential transition. * A good way to achieve this is to construct a * higher level graph, using traces as nodes. * An arc is added between traces whose head * and tail are connected by a transition. */ static void PlaceTraces (FGraph graph) { FGraph new_graph; Node node, current; Node node_order[MAX_GRAPH_SIZE]; int i, size; #ifndef SECOND_LEVEL_SELECT int min_trace_id, max_trace_id; #endif if (graph->nodes == 0) return; #ifdef SECOND_LEVEL_SELECT new_graph = NewGraph (); /* create a high level graph */ for (node = graph->nodes; node != 0; node = nextNode (node)) { int trace_id; Node temp; trace_id = nodeType (node); temp = FindNode (new_graph, trace_id); if (temp == 0) { temp = NewNode (); nodeId (temp) = trace_id; AddNode (new_graph, temp); } if (node == graph->root) new_graph->root = temp; } for (node = graph->nodes; node != 0; node = nextNode (node)) { Arc arc; if (!(nodeStatus (node) & TRACE_TAIL)) continue; /* * Find transitions to the head of other traces. * Inner loop back-edge is not considered. */ for (arc = destinationArcs (node); arc != 0; arc = nextArc (arc)) { Node dest; dest = destinationNode (arc); if ((nodeType (dest) != nodeType (node)) && (nodeStatus (dest) & TRACE_HEAD)) { /* * Add a link (trace[node]->trace[dest]) */ int src_trace_id, dest_trace_id; Node src_node, dest_node; Arc ar; src_trace_id = nodeType (node); dest_trace_id = nodeType (dest); src_node = FindNode (new_graph, src_trace_id); dest_node = FindNode (new_graph, dest_trace_id); ConnectNodes (src_node, dest_node, 0); ar = FindSrcArc (src_node, dest_node, 0); arcWeight (ar) = arcWeight (arc); ar = FindDestArc (src_node, dest_node, 0); arcWeight (ar) = arcWeight (arc); } } } /* * Simply assign the node weights to max(connecting arc) */ for (node = new_graph->nodes; node != 0; node = nextNode (node)) { Arc arc; double max = 1.0; for (arc = sourceArcs (node); arc != 0; arc = nextArc (arc)) if (arcWeight (arc) > max) max = arcWeight (arc); for (arc = destinationArcs (node); arc != 0; arc = nextArc (arc)) if (arcWeight (arc) > max) max = arcWeight (arc); nodeWeight (node) = max; } /* * Apply SelectTraces() on the new graph. * Use SELECT_BY_ARC_WEIGHT */ best_successor_of = best_successor_2; best_predecessor_of = best_predecessor_2; SelectTraces (new_graph); /* * Determine the best sequential order of the traces. * Essentially, we have the original problem again. * However, after the second level trace selection, * we expect most of the sequential transitions are * captured. A naive heuristic is sufficient here. * The sequential order must start with the ENTRY trace. */ #ifdef DEBUG_TRACE1 printf ("... second level graph = \n"); WriteGraph ("stdout", new_graph); #endif /* * Clear the valid bit of all nodes. */ for (node = new_graph->nodes; node != 0; node = nextNode (node)) { nodeStatus (node) &= ~VISITED; } /* * Start from the root node. */ size = 0; current = new_graph->root; while (current != 0) { Node ptr; Arc ar; int trace_id; if (nodeStatus (current) & VISITED) Punt ("PlaceTraces: reached a VISITed node"); nodeStatus (current) |= VISITED; trace_id = nodeId (current); /* * Layout the trace. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if ((nodeType (ptr) == trace_id) && (nodeStatus (ptr) & TRACE_HEAD)) break; /* find the starting node of the trace */ } if (ptr == 0) Punt ("PlaceTraces: internal error (1)"); while (ptr != 0) { Arc next; node_order[size++] = ptr; /* * Follow the in-trace transition. */ if (nodeStatus (ptr) & TRACE_TAIL) break; /* reached the end of trace */ for (next = destinationArcs (ptr); next != 0; next = nextArc (next)) { if (arcType (next) == nodeType (ptr)) break; /* find a in-trace transition */ } if (next == 0) break; ptr = destinationNode (next); } /* * Select the next trace to be visited next. * Follow an in-trace transition (of the higher level * graph) if possible. */ for (ar = destinationArcs (current); ar != 0; ar = nextArc (ar)) { if (arcType (ar) == nodeType (current)) break; /* find an in-trace transition */ } if (ar != 0) { /* transition is still in-trace */ current = destinationNode (ar); } else { /* must find another trace */ /* * Find the most important trace left. */ Node nn, best; best = 0; for (nn = new_graph->nodes; nn != 0; nn = nextNode (nn)) { if (nodeStatus (nn) & VISITED) continue; /* skip over VISITED nodes */ if (!(nodeStatus (nn) & TRACE_HEAD)) continue; /* skip over non-trace headers */ if (best == 0) { best = nn; } else { if (nodeWeight (nn) > nodeWeight (best)) best = nn; } } current = best; /* go out of trace if best=0 */ } } /* * Make sure that all traces have been layout. */ for (node = new_graph->nodes; node != 0; node = nextNode (node)) { if (!(nodeStatus (node) & VISITED)) { Punt ("PlaceTraces: missing some traces"); } } /* * No longer need the higher level graph. */ FreeGraph (&new_graph); /* destroy the high level graph */ #else min_trace_id = 0x1FFFFFFF; max_trace_id = -0x1FFFFFFF; for (node = graph->nodes; node != 0; node = nextNode (node)) { int trace_id; trace_id = nodeType (node); if (trace_id > max_trace_id) max_trace_id = trace_id; if (trace_id < min_trace_id) min_trace_id = trace_id; } for (node = graph->nodes; node != 0; node = nextNode (node)) { nodeStatus (node) &= ~VISITED; } size = 0; for (i = min_trace_id; i <= max_trace_id; i++) { Node ptr; /* * 1. find the trace header. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if ((nodeType (ptr) == i) & ((nodeStatus (ptr) & TRACE_HEAD) != 0)) break; } if (ptr == 0) continue; while (ptr != 0) { Arc next; if (nodeStatus (ptr) & VISITED) Punt ("PlaceTraces: visited a node twice"); nodeStatus (ptr) |= VISITED; node_order[size++] = ptr; if (nodeStatus (ptr) & TRACE_TAIL) break; for (next = destinationArcs (ptr); next != 0; next = nextArc (next)) { if (arcType (next) == nodeType (ptr)) break; } if (next == 0) break; ptr = destinationNode (next); } } /* * Make sure that all traces have been layout. */ for (node = graph->nodes; node != 0; node = nextNode (node)) { if (!(nodeStatus (node) & VISITED)) { fprintf (stderr, "min trace id = %d\n", min_trace_id); fprintf (stderr, "max trace id = %d\n", max_trace_id); fprintf (stderr, "size = %d\n", size); WriteGraph ("stderr", graph); Punt ("PlaceTraces: missing some traces"); } } #endif /* * Rearrange the order of nodes, according to the * node_order[] order. */ node_order[size] = 0; for (i = 0; i < size; i++) { nextNode (node_order[i]) = node_order[i + 1]; } graph->nodes = node_order[0]; }
static void AddExtensionFields (FGraph graph) { Node ptr; Arc arc; struct Ext *ext; int change; Set all; FreeExtensionFields (); if (graph->nodes == 0) return; if (graph->root == 0) Punt ("no root node"); all = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { nodeExt (ptr) = (others + n_others); others[n_others].dominator = 0; others[n_others].level = -1; others[n_others].order = n_others; all = Set_add (all, n_others); n_others += 1; } ext = (struct Ext *) nodeExt (graph->root); ext->level = 0; ext->dominator = Set_add (0, ext->order); for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if (ptr == graph->root) continue; ext = (struct Ext *) nodeExt (ptr); ext->dominator = Set_union (0, all); } /* * compute dominators. */ change = 1; while (change != 0) { change = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { Set dom, temp; if (ptr == graph->root) continue; arc = sourceArcs (ptr); if (arc == 0) { dom = 0; } else { dom = Set_union (all, 0); for (; arc != 0; arc = nextArc (arc)) { ext = (struct Ext *) nodeExt (sourceNode (arc)); temp = Set_intersect (dom, ext->dominator); Set_dispose (dom); dom = temp; temp = 0; } ext = (struct Ext *) nodeExt (ptr); dom = Set_add (dom, ext->order); if (Set_same (dom, ext->dominator)) { Set_dispose (dom); } else { Set_dispose (ext->dominator); ext->dominator = dom; change += 1; } } } } all = Set_dispose (all); /* * compute level. */ change = 1; while (change != 0) { change = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { int max; ext = (struct Ext *) nodeExt (ptr); if (ext->level >= 0) continue; max = -1; for (arc = sourceArcs (ptr); arc != 0; arc = arc->next) { Node src; struct Ext *ex; src = sourceNode (arc); ex = (struct Ext *) nodeExt (src); /* ignore back-edges */ if (ex->order >= ext->order) continue; if (ex->level < 0) break; if (ex->level > max) max = ex->level; } if (arc == 0) { /* all source have been visited */ ext->level = max + 1; change += 1; } } } #ifdef DEBUG printf ("--------------------------------------------------\n"); for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { ext = nodeExt (ptr); printf ("# id=%d, order=%d, level=%d, ", ptr->id, ext->order, ext->level); PrintSet (stdout, "dominator", ext->dominator); } #endif }
/* * Trace selection by sorting all arcs and * select from the most important to the least important. */ void SelectBySortArc (FGraph graph) { #define MAX_SIZE (MAX_GRAPH_SIZE*2) ST_Entry sorted_list[MAX_SIZE]; /* expected fan-out = 2 */ register int list_length; Node node_list[MAX_GRAPH_SIZE]; register int node_list_length; register Node ptr; register Arc arc; register int i; int next_trace_id; /* * Mark all nodes unvisited. * Also clear all status bits. */ node_list_length = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { node_list[node_list_length++] = ptr; if (node_list_length >= MAX_GRAPH_SIZE) Punt ("SelectBySortArc: graph is too large"); nodeType (ptr) = 0; /* trace id = 0 */ nodeStatus (ptr) = NOT_VISITED; for (arc = sourceArcs (ptr); arc != 0; arc = nextArc (arc)) arcType (arc) = 0; for (arc = destinationArcs (ptr); arc != 0; arc = nextArc (arc)) arcType (arc) = 0; } /* * Place all outgoing arcs in the list. * Sort all arcs by weight. */ list_length = 0; for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { for (arc = destinationArcs (ptr); arc != 0; arc = nextArc (arc)) { sorted_list[list_length].weight = arcWeight (arc); sorted_list[list_length].ptr = arc; list_length += 1; if (list_length >= MAX_SIZE) Punt ("SelectBySortArc: graph is too large"); } } max_sort (sorted_list, list_length); /* library/sort.c */ /* * From the most important arc to the least important arc, * connect basic blocks into traces. */ next_trace_id = 1; for (i = 0; i < list_length; i++) { int trace_id; Node src, dest; arc = (Arc) sorted_list[i].ptr; src = sourceNode (arc); dest = destinationNode (arc); /* * Check if this arc can still be selected. * dest cannot be the root of the graph. * case1 : src = free node, dest = free node * case2 : src is a tail node, dest is a head node, * except when src and dest belong to the same trace. */ if (dest == graph->root) continue; if (! ((nodeStatus (src) == NOT_VISITED) || (nodeStatus (src) & TRACE_TAIL))) continue; if (! ((nodeStatus (dest) == NOT_VISITED) || (nodeStatus (dest) & TRACE_HEAD))) continue; /* * If both src and dest are defined (in some trace), * we do not allow this connection if src and dest * belong to the same trace. * This takes care of self-recursions. */ if ((nodeStatus (src) & TRACE_TAIL) && (nodeStatus (dest) & TRACE_HEAD)) if (nodeType (src) == nodeType (dest)) continue; /* * It is also not allow to connect, when src and dest * are the same node. */ if (src == dest) continue; /* * After connection, src will no longer be tail, and * dest will no longer be head. */ nodeStatus (src) &= ~TRACE_TAIL; nodeStatus (dest) &= ~TRACE_HEAD; /* * Now this arc can be selected. */ if (nodeStatus (src) & VISITED) { trace_id = nodeType (src); arcType (arc) = trace_id; /* * If the dest node is in another trace, need to * combine the two traces. */ if (nodeStatus (dest) & VISITED) { register int j; register int bad_id = nodeType (dest); /* * For all nodes of type (nodeType(dest)), change * to trace_id. */ for (j = 0; j < node_list_length; j++) if (nodeType (node_list[j]) == bad_id) nodeType (node_list[j]) = trace_id; /* * For all arcs of type (nodeType(dest)), change * to trace_id. */ for (j = 0; j < list_length; j++) { Arc ac; ac = (Arc) sorted_list[j].ptr; if (arcType (ac) == bad_id) arcType (ac) = trace_id; } } else { /* * If dest is still a free node, it becomes the * trace tail. */ nodeStatus (dest) |= (VISITED | TRACE_TAIL); nodeType (dest) = trace_id; } } else if (nodeStatus (dest) & VISITED) { trace_id = nodeType (dest); arcType (arc) = trace_id; /* * Since src is a free node, src becomes a trace head. */ nodeStatus (src) |= (VISITED | TRACE_HEAD); nodeType (src) = trace_id; } else { trace_id = next_trace_id++; arcType (arc) = trace_id; nodeStatus (src) |= (VISITED | TRACE_HEAD); nodeType (src) = trace_id; nodeStatus (dest) |= (VISITED | TRACE_TAIL); nodeType (dest) = trace_id; } } /* * The remaining NOT_VISITED nodes, each forms a trace. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if (nodeStatus (ptr) & VISITED) continue; nodeStatus (ptr) |= (VISITED | TRACE_HEAD | TRACE_TAIL); nodeType (ptr) = next_trace_id++; } /* * Detect inner loops. */ for (ptr = graph->nodes; ptr != 0; ptr = nextNode (ptr)) { if (!(nodeStatus (ptr) & TRACE_TAIL)) continue; for (arc = destinationArcs (ptr); arc != 0; arc = nextArc (arc)) { Node dest; dest = destinationNode (arc); if ((nodeStatus (dest) & TRACE_HEAD) && (nodeType (dest) == nodeType (ptr))) { nodeStatus (dest) |= LOOP_HEAD; break; } } } }
Module::ReturnType SubgraphUpwardPlanarizer::doCall(UpwardPlanRep &UPR, const EdgeArray<int> &cost, const EdgeArray<bool> &forbid) { const Graph &G = UPR.original(); GraphCopy GC(G); //reverse some edges in order to obtain a DAG List<edge> feedBackArcSet; m_acyclicMod.get().call(GC, feedBackArcSet); for(edge e : feedBackArcSet) { GC.reverseEdge(e); } OGDF_ASSERT(isSimple(G)); //mapping cost EdgeArray<int> cost_GC(GC); for(edge e : GC.edges) { if (forbid[GC.original(e)]) cost_GC[e] = numeric_limits<int>::max(); else cost_GC[e] = cost[GC.original(e)]; } // tranform to single source graph by adding a super source s_hat and connect it with the other sources EdgeArray<bool> sourceArcs(GC, false); node s_hat = GC.newNode(); for(node v : GC.nodes) { if (v->indeg() == 0 && v != s_hat) { edge e_tmp = GC.newEdge(s_hat, v); cost_GC[e_tmp] = 0; // crossings source arcs cause not cost sourceArcs[e_tmp] = true; } } /* //------------------------------------------------debug GraphAttributes AG_GC(GC, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); AG_GC.setAllHeight(30.0); AG_GC.setAllWidth(30.0); for(node z : AG_GC.constGraph().nodes) { AG_GC.label(z) = to_string(z->index()); } AG_GC.writeGML("c:/temp/GC.gml"); // --------------------------------------------end debug */ BCTree BC(GC); const Graph &bcTree = BC.bcTree(); GraphCopy G_dummy; G_dummy.createEmpty(G); NodeArray<GraphCopy> biComps(bcTree, G_dummy); // bicomps of G; init with an empty graph UpwardPlanRep UPR_dummy; UPR_dummy.createEmpty(G); NodeArray<UpwardPlanRep> uprs(bcTree, UPR_dummy); // the upward planarized representation of the bicomps; init with an empty UpwarPlanRep constructComponentGraphs(BC, biComps); for(node v : bcTree.nodes) { if (BC.typeOfBNode(v) == BCTree::CComp) continue; GraphCopy &block = biComps[v]; OGDF_ASSERT(m_subgraph.valid()); // construct a super source for this block node s, s_block; hasSingleSource(block, s); s_block = block.newNode(); block.newEdge(s_block, s); //connect s UpwardPlanRep bestUPR; //upward planarize if not upward planar if (!UpwardPlanarity::upwardPlanarEmbed_singleSource(block)) { for (int i = 0; i < m_runs; i++) {// i multistarts UpwardPlanRep UPR_tmp; UPR_tmp.createEmpty(block); List<edge> delEdges; m_subgraph.get().call(UPR_tmp, delEdges); OGDF_ASSERT( isSimple(UPR_tmp) ); UPR_tmp.augment(); //mark the source arcs of block UPR_tmp.m_isSourceArc[UPR_tmp.copy(s_block->firstAdj()->theEdge())] = true; for (adjEntry adj_tmp : UPR_tmp.copy(s_block->firstAdj()->theEdge()->target())->adjEntries) { edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); if (e_tmp != nullptr && block.original(e_tmp) != nullptr && sourceArcs[block.original(e_tmp)]) UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; } //assign "crossing cost" EdgeArray<int> cost_Block(block); for (edge e : block.edges) { if (block.original(e) == nullptr || GC.original(block.original(e)) == nullptr) cost_Block[e] = 0; else cost_Block[e] = cost_GC[block.original(e)]; } /* if (false) { //---------------------------------------------------debug LayerBasedUPRLayout uprLayout; UpwardPlanRep upr_bug(UPR_tmp.getEmbedding()); adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); node s_upr_bug = upr_bug.newNode(); upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); upr_bug.m_isSourceArc.init(upr_bug, false); upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; upr_bug.s_hat = s_upr_bug; upr_bug.augment(); GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); GA_UPR_tmp.setAllHeight(30.0); GA_UPR_tmp.setAllWidth(30.0); uprLayout.call(upr_bug, GA_UPR_tmp); // label the nodes with their index for(node z : GA_UPR_tmp.constGraph().nodes) { GA_UPR_tmp.label(z) = to_string(z->index()); GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); } for(edge eee : GA_UPR_tmp.constGraph().edges) { DPolyline &line = GA_UPR_tmp.bends(eee); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; (*it).m_x = -(*it).m_x; } } GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); cout << "UPR_tmp/fups faces:"; UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); //end -----------------------------------------------debug } */ delEdges.permute(); m_inserter.get().call(UPR_tmp, cost_Block, delEdges); if (i != 0) { if (UPR_tmp.numberOfCrossings() < bestUPR.numberOfCrossings()) { //cout << endl << "new cr_nr:" << UPR_tmp.numberOfCrossings() << " old cr_nr : " << bestUPR.numberOfCrossings() << endl; bestUPR = UPR_tmp; } } else bestUPR = UPR_tmp; }//for } else { //block is upward planar CombinatorialEmbedding Gamma(block); FaceSinkGraph fsg((const CombinatorialEmbedding &) Gamma, s_block); SList<face> faceList; fsg.possibleExternalFaces(faceList); Gamma.setExternalFace(faceList.front()); UpwardPlanRep UPR_tmp(Gamma); UPR_tmp.augment(); //mark the source arcs of block UPR_tmp.m_isSourceArc[UPR_tmp.copy(s->firstAdj()->theEdge())] = true; for (adjEntry adj_tmp : UPR_tmp.copy(s->firstAdj()->theEdge()->target())->adjEntries) { edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); if (e_tmp != nullptr && block.original(e_tmp) != nullptr && sourceArcs[block.original(e_tmp)]) UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; } bestUPR = UPR_tmp; /* //debug //---------------------------------------------------debug GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); GA_UPR_tmp.setAllHeight(30.0); GA_UPR_tmp.setAllWidth(30.0); // label the nodes with their index for(node z : GA_UPR_tmp.constGraph().nodes) { GA_UPR_tmp.label(z) = to_string(z->index()); GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); } for(edge eee : GA_UPR_tmp.constGraph().edges) { DPolyline &line = GA_UPR_tmp.bends(eee); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; (*it).m_x = -(*it).m_x; } } GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); cout << "UPR_tmp/fups faces:"; UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); //end -----------------------------------------------debug */ } uprs[v] = bestUPR; } // compute the number of crossings int nr_cr = 0; for(node v : bcTree.nodes) { if (BC.typeOfBNode(v) != BCTree::CComp) nr_cr = nr_cr + uprs[v].numberOfCrossings(); } //merge all component to a graph node parent_BC = BC.bcproper(s_hat); NodeArray<bool> nodesDone(bcTree, false); dfsMerge(GC, BC, biComps, uprs, UPR, nullptr, parent_BC, nodesDone); // start with the component which contains the super source s_hat //augment to single sink graph UPR.augment(); //set crossings UPR.crossings = nr_cr; //------------------------------------------------debug /* LayerBasedUPRLayout uprLayout; UpwardPlanRep upr_bug(UPR.getEmbedding()); adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); node s_upr_bug = upr_bug.newNode(); upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); upr_bug.m_isSourceArc.init(upr_bug, false); upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; upr_bug.s_hat = s_upr_bug; upr_bug.augment(); GraphAttributes AG(UPR, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); AG.setAllHeight(30.0); AG.setAllWidth(30.0); uprLayout.call(upr_bug, AG); for(node v : AG.constGraph().nodes) { int idx; idx = v->index(); if (UPR.original(v) != 0) idx = UPR.original(v)->index(); AG.label(v) = to_string(idx); if (UPR.isDummy(v)) AG.fillColor(v) = "#ff0000"; AG.y(v)=-AG.y(v); } // label the edges with their index for(edge e : AG.constGraph().edges) { AG.label(e) = to_string(e->index()); if (UPR.isSourceArc(e)) AG.strokeColor(e) = "#00ff00"; if (UPR.isSinkArc(e)) AG.strokeColor(e) = "#ff0000"; DPolyline &line = AG.bends(e); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; } } AG.writeGML("c:/temp/upr_res.gml"); //cout << "UPR_RES"; //UPR.outputFaces(UPR.getEmbedding()); //cout << "Mapping :" << endl; //for(node v : UPR.nodes) { // if (UPR.original(v) != 0) { // cout << "node UPR " << v << " node G " << UPR.original(v) << endl; // } //} // --------------------------------------------end debug */ OGDF_ASSERT(hasSingleSource(UPR)); OGDF_ASSERT(isSimple(UPR)); OGDF_ASSERT(isAcyclic(UPR)); OGDF_ASSERT(UpwardPlanarity::isUpwardPlanar_singleSource(UPR)); /* for(edge eee : UPR.original().edges) { if (UPR.isReversed(eee)) cout << endl << eee << endl; } */ return Module::retFeasible; }