In 1963, Knuth published the first paper on a computer algorithm for a graph drawing problem, entitled “Computer-drawn Flowcharts” . In this paper, Knuth describes an algorithm that takes as input an -vertex directed graph that represents a flowchart and, using the modern language of graph drawing, produces an orthogonal drawing of , where vertices are assigned to integer grid points and edges are polygonal paths of horizontal and vertical segments. In Knuth’s algorithm, every vertex is given the same -coordinate and every edge has at most bends, so that drawings produced using his algorithm can be output line-by-line on an (old-style) ASCII line printer and have worst-case area at most . Some drawbacks of his approach are that his drawings can be highly non-planar, even if the graph is planar, and his drawings can have very poor aspect ratios, since every vertex is drawn along a vertical line. Nevertheless, his drawings possess an additional desirable property that has not been specifically addressed since the time of his seminal paper, which we revisit in this paper.
Specifically, inspired by his drawing convention, we say that a directed orthogonal graph drawing is Knuthian if there is no vertex having an incident edge locally pointing upwards unless that vertex is a junction node, that is, a vertex having in-degree strictly greater than its out-degree. In other words, a directed orthogonal graph drawing is Knuthian if no non-junction node has an in-coming edge into its bottom or an out-going edge out of its top. This property (rotated 180 degrees) is related to previously-studied concepts known as “upward” or “quasi-upward” drawing conventions [3, 4, 5], where all edges must locally enter a vertex from below and leave going up. Intuitively, Knuthian drawings have a natural top-to-bottom flow through non-junction nodes while allowing for natural reverse-directional flow through junction nodes.
A Knuthian drawing is different from upward and quasi-upward drawing conventions in that a Knuthian drawing places no orientation constraints on the edges incident to junction nodes. In other words, a Knuthian drawing is a hybrid between a quasi-upward orthogonal drawing (rotated 180) and an unconstrained orthogonal drawing, and this hybrid nature raises some interesting graph drawing questions.
In this paper, we describe efficient algorithms for producing Knuthian drawings of degree-three series-parallel directed graphs, which are equivalent to the flowcharts of loop-free algorithms. We provide a recursive linear-time algorithm for producing such drawings of degree-three series-parallel graphs and we show that such a graph with vertices has a Knuthian drawing with width and height . We then show how to “wrap” this drawing, while still maintaining it to be Knuthian, to fit within a fixed width, so that the area is and the aspect ratio is constant. Our drawings strive to achieve few edge bends, both in the aggregate and per edge. Our drawing approach contrasts with previous approaches to drawing series-parallel graphs, including the standard recursive split-join-and-compose method and Knuth’s original method , as well as more recent methods for drawing series-parallel graphs (e.g., see [2, 1, 6]). For example, we are able to match the two-bends-per-edge bound achieved by Biedl  while at the same time improving the area of the drawing, by exploiting the area improvements possible using the Knuthian drawing convention. Admittedly, our Knuthian drawings are not always upward, but they nevertheless achieve an “upward-like” quality through the careful use of junction nodes.
2 Classic Algorithms
Two classic algorithms for drawing series-parallel flowcharts are the standard split-join-and-compose algorithm and Knuth’s algorithm . We review both of these algorithms in this section.
In the standard split-join-and-compose algorithm for drawing a series-parallel flowchart, we draw the graph recursively according to recursive structure of the graph in a left-to-right or top-down fashion (w.l.o.g., let us assume a left-to-right orientation). Two graph components formed as a parallel construction are drawn recursively along two side-by-side horizontal strips, which are connected to a split node with in-coming edge from the left and outgoing vertical edges that each bend at the in-coming segment for the strip. Each outgoing edge is drawn as a horizontal line that bends to join back at a junction node having the same -coordinate as the split node. Series constructions are simply composed left-to-right and connected by horizontal segments. Such graphs are degree-three series-parallel graphs, because they correspond to the control flow of a loop-free algorithm, which contains sequences of statements and (possibly-nested) if-then-else decision constructs. (See Figure 1 for two examples.)
In Knuth’s algorithm, we place all of the nodes in a single column along the left side of the drawing (to all have the same -coordinate) using some reasonable ordering of the vertices. We then draw each edge in a top-to-bottom greedy fashion using the space to the right of this column. If an edge is between two consecutive nodes in the column, we simply connect these two nodes with a single vertical segment. Otherwise, we draw an edge , with coming after , to go horizontally out from (optionally after a first short downward segment from ), bending to go vertically down to a row for , and then extending horizontally back to (optionally adding a short vertical segment going into the top of ). An edge , with coming before , is drawn in a similar fashion, except that the edge is drawn in reverse direction and the optional short vertical segments would be coming into from above and going out from below . (See Figure 2 for two examples.)
These algorithms both have the drawback of requiring area in the worst case. For Knuth’s algorithm, we will always have height . In the worst case, as exemplified in Figure 3, we may have to use distinct columns for edges, which may force the width to also be in the worst case. Alternatively, for large graphs using a small number of columns, the aspect ratios of their drawings can be quite bad, as shown in Figure 2.
To see that the standard split-join-and-compose algorithm also uses area, note that we may have graph with nodes in series, followed by nodes in parallel. Then the height (in a left-to-right orientation) will be , because the parallel nodes will all be stacked on top of one another, while the width will also be , because of the series nodes drawn along the same horizontal strip. (See Figure 4.)
3 Knuthian Drawings of Series-Parallel Flowcharts with Area
In this section, we show that any -vertex degree-three series-parallel graph has a Knuthian drawing with area. In Appendix A, we discuss how to implement this drawing in linear time. We achieve this area bound using a Knuthian drawing scheme that uses width and height, and we show in the next section how to improve the aspect ratios for such drawings while maintaining an area bound.
Let be a series-parallel graph with nodes. begins with nodes in series until it reaches its first split node for two parallel subgraphs. Likewise, ends with nodes in series after its last junction joining two parallel subgraphs. We can categorize as being one of two types, which we respectively call “broad” and “pinched,” as illustrated in Figure 5. In the broad case (the upper graph in Figure 5), the first parallel split after the initial series nodes divides into series-parallel subgraphs of size and , respectively, and this parallel split is joined just before the last series nodes. In the pinched case (the lower graph in Figure 5), the first parallel split after the initial series nodes (into subgraphs of size and , respectively) is not joined just before the last series nodes, and instead there is a subgraph of nodes occurring between a last parallel split (just prior to the last series nodes), which is divided into subgraphs of size and .
Let us first consider the broad case. We assume, without loss of generality, that . Then we draw the graph recursively as in Figure 6, possibly with one additional bend for the incoming and outgoing edges for the subgraph of size , for the incoming edge to enter in the upper left and the outgoing edge to exit in the lower left.
Repeating this process results in a drawing pattern as illustrated in Figure 7.
Let us next consider the pinched case. We assume, without loss of generality, that and that . Then we take the largest of , , and , and recursively draw its corresponding subgraph on the far right side, so that it can take up the full height of the drawing. Figure 8 shows how to recursively draw each of the respective cases in which , , or are the largest.
This algorithm results in the following.
A degree-three series-parallel graph with vertices has a Knuthian drawing with width and height , such that each edge has at most two bends and the total number of bends is at most .
Assume we have a degree-three series-parallel graph with nodes. Recall that Figure 5 shows the two possible types of series-parallel graphs, broad and pinched, that we consider. Let’s take the first of these types, the broad case, where, we assume, without loss of generality, that , and we draw the graph recursively as in Figure 6. In this case, the width, , is clearly , which is . The required height, , in this case is . Since , we have , so , when in this case.
Now take the second case, of a pinched subgraph. Assume without loss of generality that and that . Then we take the largest of , and draw it on the far right side, so that it can take up the full height of the drawing, as shown in Figure 8. In each of these cases, it is easy to see that the width, , is . In the first of these cases, the total height, , is at most
We know, in this case, that and are each at most , and that . In addition, similar bounds hold for the second and third cases, implying that , when in any of these cases. Thus, this bound applies independent of whether we are in the broad or pinched cases. Therefore, is .
To establish the bound on the number of bends per edge, notice that the number of bends per edge is zero in our pattern for Figure 6. There is also a base case (not shown), when we have only series nodes, which may introduce 1 bend (in the case of a single node). The number of bends per edge in any of our patterns in Figure 8 is at most two, even considering a base case when , or . Moreover, the in-coming edges into an upper left corner of a pattern can come from above or from the left, but we can “slide” an origin node in each case so that we don’t introduce any new bends per edge no matter if we are entering a pattern from the left or from above. Likewise, a similar argument applies to the edge leaving a pattern that goes out to the left or down. Thus, the number of bends per edge in our final drawing is at most two.
To establish the bound on the total number of bends, notice that our pattern in Figure 5 does not introduce any bends, and the unshown base case of a single node introduces at most 1 bend. Each of our patterns in Figure 8 introduces at most 5 bends. Moreover, each pattern in Figure 8 places at least 4 graph vertices into the drawing (even if and ). Therefore, we may account for all the bends we introduce by using an amortization scheme where we charge each node in any of our patterns (including the unshown base case) for 1.25 bends. This results in a total number of bends. ∎
In an appendix, we show how this drawing can be computed in linear time.
4 Fixed-Width Drawings
In this section, we show how to adapt our -area drawings, which admittedly have poor aspect ratios, so that they achieve constant aspect ratios, proving the following theorem.
A degree-three series-parallel graph with nodes has a Knuthian drawing that can be produced in linear time to have width and height , for any given ; hence, the area is . The total number of bends is at most .
|Rotated orientation adjustments|
|Node type||Previous orientation||rotation||Total bends added|
Our proof is based on taking our single-row drawing from Theorem 3.1 and performing a sequence of transformations that intuitively involve our dividing the drawing into “slabs” and then “folding” those slabs to achieve a good aspect ratio. The main details of the proof involve describing the changes necessary in order to maintain the Knuthian-drawing property even as we rotate a slab by .
Let us assume, then, that we are given a drawing of our degree-three series-parallel graph as in Theorem 3.1. First, we order all of the nodes by their -coordinate, breaking ties by their -coordinate. Then we take this list and divide it into slabs with exactly nodes (the last slab being somewhat smaller, if necessary).
Next, we stack these sections above one another, with every other section rotated , and reconnect all of the edges that were cut, as shown in Figure 10. Since our single-row drawing had height , there are at most of these edges.
Lastly, we have to make sure that the nodes in each rotated section still satisfy our requirements for a Knuthian drawing. This requires adding bends to the incoming and outgoing edges at some of our decision and process nodes. The junction nodes do not have any restrictions on the locations of incoming or outgoing edges, so no changes to them are necessary. The table shown in Figure 9 shows all of the possible connections, and how we choose to redraw them. By inspection, it should be clear that performing these transformations imply that the resulting drawing is Knuthian. Adding the bends will increase the width of our graph, but only by a small constant factor. The width of each slab’s transformed section is , plus for the extended edges. The height of each section is , times sections. This establishes the claimed width and height bounds for the theorem.
Finally, we prove the claim that our drawing has at most bends. Recall that our original drawing had at most bends. Then we have added additional bends for the edges between sections, for the process nodes, and for the decision nodes.
First, we count bends for the edges between our sections of size . There are of these sections, and edges between them, each of which has two additional bends. This gives a total of additional bends. However, since we will choose to be larger that , this will be a lower-order term, which we will ignore. Second, we count bends for the process nodes. There are nodes in the rotated sections, and from our table we see that each could have up to two extra bends. This adds a total of up to bends. Third, we count bends for the decision nodes. We charge the first decision node in each section to the previous recursive level, since the previous level determines from what direction we enter.
In the broad case, we ignore the first decision node and only count the two for the two subsections. The decision node for the larger subsection will take two bends, while the decision node for the smaller subsection could take three. This gives an average of bends per decision node. In our diagram for the pinched case, three of the five sections have edges entering from the top, and will take three extra bends to fix when they are rotated. The other two will only take two bends. We then have two other decision nodes, but as stated, the first of these is already charged to the previous level. The other adds another two bends. This gives a total of 15 bends charged to six decision nodes, or once again, bends per decision node. To finish, we need to count the total number of decision nodes in each section. This is bounded by the number of process nodes in the section, plus the difference between the number of edges leaving and entering the section. In our case, this is dominated by , the number of process nodes in the section. Since half of our sections are rotated, we have at most rotated decision nodes, for a total of extra bends. So to sum up, we get bends from the original graph, new bends between the sections, new bends from the process nodes, and new bends from the decision nodes, for a total of bends. ∎
5 Experimental results
We implemented and tested our Knuth drawing algorithm algorithm on some sample degree-three series-parallel graphs, based on two distributions used to create random binary series-parallel decomposition trees. The first case is defined by three parameters: , the number of nodes;
, the probability that an internal node is a parallel composition (rather than series); and, the expected fractional size of the left subtree. To construct the tree, we first choose a root node, and set it to a parallel composition with probability and a series composition with probability . Then we sample
from the normal distribution with mean. The size of the left subtree is then , and the size of the right subtree is then . This process is then repeated recursively for the left and right subtrees. We reach our base case when , in which case we let the subtree consist of a single leaf node.
The second version is defined by just the first two parameters, and
, as above. But instead of using a normal distribution to determine the size of each subtree, we use a uniform distribution.
We performed experiments by running 300 random inputs through our algorithm for small-area drawing, Knuth’s algorithm, and the standard split-join-and-compose algorithm for graphs of 10, 20, 50, 100, 200, 500, and 1000 nodes, respectively. We show the results of these experiments in Figures 11 and 12. The first nine charts were created using the first notion of randomness, with varying values of and . The last three charts were created using the second notion of randomness, with varying values of . The unit length used in all of the tests was 30. Each chart has been set to use the same vertical axis for easy visual comparison between charts.
Our experiments provide evidence that our algorithm produces a drawing that is anywhere from slightly smaller up to eight times smaller than the previous two algorithms. One conclusion that can be drawn from these results is that the size of our drawing is not affected greatly by the parameters, while the sizes of the other two drawings increase quickly as the number of parallel splits increases.
This research was supported in part by the National Science Foundation under grants 1011840 and 1228639. This article also reports on work supported by the Defense Advanced Research Projects Agency (DARPA) under agreement no. AFRL FA8750-15-2-0092. The views expressed are those of the authors and do not reflect the official policy or position of the Department of Defense or the U.S. Government.
-  P. Bertolazzi, R. F. Cohen, G. Di Battista, R. Tamassia, and I. G. Tollis. How to draw a series-parallel digraph. International Journal of Computational Geometry & Applications, 04(04):385–402, 1994.
-  T. Biedl. Small drawings of outerplanar graphs, series-parallel graphs, and other planar graphs. Discrete & Computational Geometry, 45(1):141–160, 2011.
-  T. M. Chan, M. T. Goodrich, S. Kosaraju, and R. Tamassia. Optimizing area and aspect ratio in straight-line orthogonal tree drawings. Computational Geometry, 23(2):153 – 162, 2002.
-  G. Di Battista, W. Didimo, M. Patrignani, and M. Pizzonia. Orthogonal and quasi-upward drawings with vertices of prescribed size. In J. Kratochviyl, editor, Graph Drawing, volume 1731 of LNCS, pages 297–310. Springer, 1999.
-  A. Garg, M. T. Goodrich, and R. Tamassia. Planar upward tree drawings with optimal area. Int. J. Comput. Geom. Appl., 06(03):333–356, 1996.
-  S.-H. Hong, P. Eades, and S.-H. Lee. Drawing series parallel digraphs symmetrically☆. Computational Geometry, 17(3–4):165 – 188, 2000.
-  D. E. Knuth. Computer-drawn flowcharts. Commun. ACM, 6(9):555–563, Sept. 1963.
Appendix 0.A Appendix
In this appendix, we discuss in depth the implementation details for constructing the single-row drawing in linear time. The implementation occurs in three stages: initialization, preprocessing, and drawing. The input to the algorithm is a string representing a preorder traversal of the tree representing a degree-three series-parallel graph.
In the first stage, a decomposition tree is created in a linear-time pass over the input string. The second stage consists of determining for each node the type of graph rooted at based off of the two types of graphs in Figure 8. Recall that we named the first type of graph a broad graph, and the second type of graph a pinched graph.
The subtree at describes a broad graph if it indicates a parallel composition or if it indicates a series composition and at most one of its children is broad. Otherwise, the graph is pinched. In either case, we store pointers in that point to the nodes in the subtree of that are the roots of the subtrees for each component. In a broad graph, these pointers are for the subgraphs of sizes , , , and , respectively. In a pinched graph, we add pointers for the subgraphs of sizes , , , , , , and , respectively. We begin at the leaves and propagate the types of graphs up the tree so that only a constant amount of work is being done at each node to check the children and set pointers, so the second stage is also a linear-time operation.
Having these pointers for each node is advantageous in the third stage so that we don’t have to perform a search to find the different sections. Then as we construct each section, we store an internal representation that can be shifted to any origin point by changing a single offset value, so each shift takes constant time. We perform the actual drawing only once we know where every component belongs.
As an example, let us describe the case in which is the largest. For pinched graphs, we first construct drawings of the subgraphs of sizes and . We then draw the subgraphs of sizes and in parallel at the end of section using the left-to-right drawing style given in Figure 6.
Next we construct the drawings of the subgraphs of size and using the right-to-left, upside-down drawing style given in Figure 8. We need to construct these before constructing the drawing of the subgraph of size , because we may need to increase the height of this drawing, since it needs to be taller than and . Once we draw the subgraph of size with the correct height, we then shift the drawings for the subgraphs of size and into their proper positions. To finish the drawing, we shift the drawing of the subgraph of size to the end of the and section.
Finally, we draw every node at its proper location. Since there is no backtracking, each node is preprocessed once, constructed once, shifted once to fit with the other drawings in the same step, and drawn once. Thus, the overall time complexity is .