News for hackers. Stuff that matters.
Re:The Racket Blog: Dynamic Programming versus Memoization by lukev on Sunday August 26, 2012 @09:48AM (#4435066)
My lack of a formal CS background is hurting me here. Could someone speak to the distinction between a tree and a DAG they make here?

I was under the impression that the terms were more or less synonymous.

Re:The Racket Blog: Dynamic Programming versus Memoization by dkarl on Sunday August 26, 2012 @04:09PM (#4436067)
In programming lingo a tree is usually a directed acyclic graph in which every node has exactly one incoming edge (one parent) except for the root node, which has no parents. A "cycle" in a directed graph is a loop that connects a node to itself along directed edges, so "acyclic" just means there aren't any loops. In this case, that means no circular dependencies among the computations.

There's also a mathematical definition of tree which is occasionally used in theoretical CS, so you have to be careful about getting them mixed up, but that kind of tree is an undirected acyclic graph. The kind of tree they're talking about in the article is directed, because it represents computational dependencies. (If A is connected to B, then either A depends on B or B depends on A. The dependency only goes one way.)

The defining difference between a tree and a directed acyclic graph is that a node in a DAG can have more than one incoming edge. So a DAG is like a tree in which nodes can have more than one parent. Here's the simplest illustration. I can't draw arrows, but imagine each edge being directed from top to bottom, so that A is the root of the tree:

      A (a tree, therefore       A (a DAG, but not a tree)
     / \     also a DAG   )     / \
    B   C                      B   C
       /                        \ /
      D                          D
In the tree, D can have only one incoming edge (only one parent) so there can only be one path from A to D along the directed edges. In the DAG, D can have multiple incoming edges (from B and C in this case) so there can be multiple paths from A to D. Direction is important to keep in mind (and I really wish I could draw it.) Note that in the DAG, A-B-D-C-A isn't a loop because D-C-A goes against the direction of the edges: A->B->D<-C<-A. Also note that if the tree were not directed, it would be useless for representing dependencies, because it would not tell us whether C depends on A and D, or D depends on C and A depends on C, or maybe D depends on C which depends on A which depends on B. The order of the edges is what tells us that A depends on C and not vice-versa.

Here's what the article means by converting a tree into a DAG for computation. In the following illustration, I'm going to use letters to label the nodes, but different nodes in the same graph are different, even if they have the same label. Here's the tree:

        A 
       / \    
      B   C   
     /   / \
    D   E   D
     \       \
      F       F
Suppose the node labels represent computations, and the edges represent dependencies. A depends on the results of B and C, B depends on the result of D, C depends on the results of E and D, and D depends on the result of F. If you perform all the computations as they are represented in this tree, D and F will be computed twice. This might be inefficient. So you take nodes with the same labels and identify them, make them the same. That gives you a different graph which is no longer a tree:

        A 
       / \    
      B   C   
       \ / \
        D   E
         \
          F
This DAG represents the same dependencies that the tree above does, and since nodes with identical labels have been combined, each computation is represented once. The tree representation is easier to create, because you don't have to worry about finding and combining duplicate nodes, but the DAG is more efficient to compute.

The idea of memoization is that each node in the tree should be the name of a computation, and the computation itself should be looked up by name. That way even if a name occurs multiple times in the tree, the computation it names will only occur once. The computations named "B" and "C" both depend on a computation named "D" which they will look up by name. They don't have to know they share a dependency, and they don't even have to reference the same copy of the name "D". This extra layer of indirection is the "black box of memoization" that implicitly turns the tree into a DAG to avoid replicating computations D and F.

Re:The Racket Blog: Dynamic Programming versus Memoization by dkarl on Sunday August 26, 2012 @07:49PM (#4436706)
I should add: a consequence of allowing more than one incoming edge is that a DAG can have more than one "root," like this:

  A   B
   \ /
    C
With trees, if you have two roots, you'll have two disjoint trees, because there's no way for their descendants to meet without some node having multiple parents.
Re:The Racket Blog: Dynamic Programming versus Memoization by pilgrim689 on Sunday August 26, 2012 @10:23AM (#4435143)
A DAG has directed edges, whereas a tree does not. Also, a node in a tree can only have 1 parent.

Here's an example of a DAG that can't be a tree because of the edge directions:

http://en.wikipedia.org/wiki/File:Directed_acyclic_graph_3.s...

Re:The Racket Blog: Dynamic Programming versus Memoization by Evbn on Sunday August 26, 2012 @02:50PM (#4435853)
Trees are commonly directed. Single in edge per node is the important distinction.
Re:The Racket Blog: Dynamic Programming versus Memoization by pilgrim689 on Sunday August 26, 2012 @03:25PM (#4435957)
Right, but then we'd be talking about the difference between a "directed tree" and a DAG...or a "rooted tree" and a DAG. But yea, I'm sure grand-parent gets the point by now
Re:The Racket Blog: Dynamic Programming versus Memoization by lukev on Sunday August 26, 2012 @05:40PM (#4436321)
Yep, thanks. I realize that in graph theory trees aren't directed, but in programming, saying "tree" almost always implies a parent-child relationship (i.e, directedness).

I was missing that nodes in a DAG can have two "parents", that makes sense.

Re:The Racket Blog: Dynamic Programming versus Memoization by nandemo on Sunday August 26, 2012 @09:55AM (#4435085)
A tree is a DAG that is connected: if a and b are nodes of a tree, there is a path between a and b. But in general a DAG doesn't have to be connected. So all trees are DAGs but not all DAGs are trees: some are forests i.e. unions of trees.
Re:The Racket Blog: Dynamic Programming versus Memoization by ot on Sunday August 26, 2012 @10:20AM (#4435134)
That's wrong, not all connected DAGs are trees.

A DAG is a directed graph that has no (directed) loops. Consider the following:

     A
    / \
   v   v
  B     C
   \   /
    v v
     D
This is a DAG but not a tree, because it has an undirected loop but no directed loops.
Re:The Racket Blog: Dynamic Programming versus Memoization by nandemo on Sunday August 26, 2012 @11:38AM (#4435301)
You're totally right (I had a thinko and managed to miss the D in the DAG). My apologies for the misinformation.
Re:The Racket Blog: Dynamic Programming versus Memoization by qlkzy on Sunday August 26, 2012 @10:27AM (#4435154)
Trees are, in general, undirected (although it is often convenient to treat edges in rooted trees as being all directed towards or away from the root, to determine whether or not a graph is a tree it is necessary to consider the edges as undirected).

A tree is a connected undirected acyclic graph (or, equivalently, an undirected graph in which there is exactly one path between any pair of vertices).

A DAG may represent a tree (usually rooted) or it may not. Not all connected DAGs are trees e.g.:

a->b, a->c, b->d, c->d is a DAG, but not a tree.

Re:The Racket Blog: Dynamic Programming versus Memoization by shasta on Sunday August 26, 2012 @06:23PM (#4436465)
A tree is a DAG that's simply connected.