While we're on this thread, I might as well share the couple pieces I have laying around:
NB. Output a random depth vector of length y rv=: <:@(1&= # +/\)@(|.~ >:@(i: <./)@(+/\))@(A.~ ?@!@x:@#)@($&1 , $&_1@<:) NB. Pretty print a tree representation, given a depth vector (inspired by xash) TM=: 3 4 $ 0 1 0 1 3 1 3 1 2 2 2 2 pp=: |:@(,/)@({&' |o+-'@(,:~ 4 * 2&=)@({::&TM@,/\.)@(0 ,~ (=>:) + 2*=)"_ 0 ~.) The above are verbosely documented in the attached script.
NB.NB. Trees NB. NB. Collections of tools for working with generic tree data structures. NB. Formally, by "tree" we mean a "plane tree", i.e. children of a node are NB. ordered. cocurrent 'tree' NB.NB. Check whether list is a Ballot Sequences NB. NB. A "ballot sequence" S is a list of 1's and _1's that has non-negative NB. partial sums. A ballot sequence is called "strict" if the partial sums are NB. all strictly positive. NB. NB. Here are some examples: NB. NB. 1] 1 _1 1 NB. 2] 1 1 _1 _1 1 1 1 _1 1 _1 _1 _1 NB. 3] 1 1 1 1 1 1 NB. NB. Here are some non-examples: NB. NB. 1] _1 1 1 NB. 2] _1 1 1 _1 _1 1 1 1 _1 1 _1 _1 NB. 3] _1 _1 _1 _1 _1 NB. NB. Notice that 1 and 2 are cyclic rotation of the corresponding ballot NB. sequences above. bs=: (+/\ *./@:>: 0:) *. (# = _1&= +/@:+. 1&=) NB.NB. Check whether list is a Dyck Path NB. NB. A "Dyck path" of length 2n is a path on the integer lattice starting at NB. the origin (0,0) and ending at (2n,0) such that the path never dips below NB. the x-axis. NB. NB. Dyck paths can be thought of as a sort of visualization of ballot NB. sequences that sum to 0. Here is an example that corresponds to the ballot NB. sequence (1 1 _1 _1 1 1 1 _1 1 _1 _1 _1): NB. NB. 3| NB. 2| /\/\ NB. 1| /\ / \ NB. 0| / \/ \ NB. --------------- NB. 0 . . 6 . . 12. NB. NB. Since the list of x coordinates is simply (i.2n), we can elide the NB. redudancy and simply represent a Dyck path by the list of its y NB. coordinates. dp=: bs@(+/\^:_1)@}. *. (0 *./@:= {. , {:) NB.NB. Generate random depth vector of length y over its uniform distribution NB. NB. One obtains the depth vector of a tree by starting at the root, which has NB. depth 0, and walking around the perimeter counter-clockwise, writing down a NB. node's depth every time it is first encountered. Here, "node depth" means NB. its path-distance from the root. For example, the depth vector of the NB. following tree is (0 1 2 2 3 1 2): NB. NB. 0 o . NB. v < < v | ^ < < NB. 1 o ----+---- ^ NB. < < | > > > > v \ ^ NB. v +--+--+ ^ 1 o ^ NB. v | > v | ^ v | ^ NB. 2 o ^ 2 o ^ 2 o ^ NB. > > v | ^ > > NB. 3 o ^ NB. > > NB. NB. More formally, let N denote the list of nodes in depth-first pre-order NB. traversal order and (d n) denote the depth of node n in N. Then the depth NB. vector is (d N). NB. NB. The above procedure associates a unique depth vector to each tree, but it NB. is also not hard to see that the reverse is true; no two trees have equal NB. depth vectors. NB. NB. To generate a random depth vector, we exploit the fact that the set of NB. plane trees with n nodes naturally bijects with each of the following: NB. NB. 1. Dyck paths of length 2n. NB. 2. Strict ballot sequences of length 2n+1 that sum to 1, and NB. NB. Indeed, to see 1 all you have to do is walk counter-clockwise around your NB. tree again and record node depths *every* time you pass a node, not skiping NB. if it is a duplicate. Every node will be visited exactly twice, once on the NB. way down and next on the way up; you start and end at 0; and no node has NB. non-positive depth. NB. NB. For the bijection with 2, you just need to take the inverse partial sum NB. (+/\^:_1) of the Dyck path and then prepend a 1. The reason strict ballot NB. sequences are helpful here is because their cyclic permutations are all NB. unique (since there are n _1's and (1 = n *. 1+2*n) always holds). NB. NB. Better yet, it is a short lemma that any list of n 1's and n+1 _1's has NB. exactly one cyclic permutation that is a strict ballot sequence. This is NB. the key fact that we leverage here. NB. NB. So to generate a random depth vector, the following procedure should NB. suffice: NB. NB. 1. Given y, generate a random shuffle of y 1s and y-1 _1's; NB. 2. Shift that list into a strict ballot sequence; NB. 3. Turn the ballot sequence into a Dyck path; and finally NB. 4. Remove the descending steps (which correspond to node revisits). rv=: <:@(1&= # +/\)@(|.~ >:@(i: <./)@(+/\))@(A.~ ?@!@x:@#)@($&1 , $&_1@<:) rv_z_=: rv_tree_ NB.NB. Pretty print Depth Vectors as Trees NB. NB. Render depth vectors visually as their corresponding trees. For example, NB. the depth vector (0 1 2 2 3 1 2) corresponds the tree NB. NB. o -o NB. / \ |-o NB. o o | |-o NB. / \ | , which we transpose and display like | +-o . NB. o o o | +-o NB. | +-o NB. o +-o NB. NB. Conceptually, we construct this representation, level by level, in four NB. stages: NB. NB. 1. Node classification, NB. 2. Branch blacement, i.e. the vertical components in our representation, NB. 3. Stem placement, the '-' in our representation, and finally NB. 4. Formatting. NB. NB. Step 1 is easy. For each level L, we simply classify each node N into one NB. of three possible categories: NB. NB. 1. N is neither at level L nor L+1, NB. 2. N is at level L, and NB. 2. N is at level L+1. NB. NB. Step two is a bit more subtle. The key insight is to "grow" the branches NB. from their tips to their stalks by examining the node category above in NB. conjunction with the current "growth state". This latter has four NB. possibilities: NB. NB. 1. Not growing any branch. NB. 2. Branch tip, i.e. start reverse-growing a new branch, NB. 3. Branch interior, i.e. currently within a branch, NB. 4. Branch nadir, i.e. finished growing a branch, and NB. NB. This gives us a total of 12 combinations---three node categories times four NB. growth states. We start in state 1, move along the categorized nodes in NB. reverse order, and determine our next state at each step depending on the NB. combination of current state and current node category. NB. NB. We use a transition matrix to encode the transition logic, but the basic NB. ideas is that nodes at level L+1 start growing a branch from the tip and we NB. keep growing until reaching a node at level L. NB. NB. The last two steps, "stem placement" and "formatting" are quite NB. straightforward. Stems just extand out from the nodes, and formatting NB. simply typesets the internal integer representation into something visually NB. pleasing. TM=: 3 4 $ 0 1 0 1 3 1 3 1 2 2 2 2 pp=: |:@(,/)@({&' |o+-'@(,:~ 4 * 2&=)@({::&TM@,/\.)@(0 ,~ (=>:) + 2*=)"_ 0 ~.) pp_z_=: pp_tree_
---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm