Skip to content

Commit

Permalink
[docs] clarify ordering of nonlinear tape (#2401)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Jan 17, 2024
1 parent c320ca7 commit 57f09df
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions docs/src/submodules/Nonlinear/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,14 @@ julia> struct Expression
```

For each node `node` in the `.nodes` field, if `node.type` is:

* `NODE_CALL_MULTIVARIATE`, we look up
`MULTIVARIATE_OPERATORS[node.index]` to retrieve the operator
* `NODE_CALL_UNIVARIATE`, we look up
`UNIVARIATE_OPERATORS[node.index]` to retrieve the operator
* `NODE_VARIABLE`, we create `MOI.VariableIndex(node.index)`
* `NODE_VALUE`, we look up `values[node.index]`

The `.parent` field of each node is the integer index of the parent node in
`.nodes`. For the first node, the parent is `-1` by convention.

Expand All @@ -511,6 +513,16 @@ julia> expr = Expression(
);
```

The ordering of the nodes in the tape must satisfy two rules:

* The children of a node must appear after the parent. This means that the tape
is ordered topologically, so that a reverse pass of the nodes evaluates all
children nodes before their parent

This comment has been minimized.

Copy link
@rluce

rluce Jan 18, 2024

Maybe it's just semantics, but I think saying "The children of a node must appear directly after the parent" is a tad more accurate. Without "directly", you'd give room to intersperse some other node between the node and its children.

This comment has been minimized.

Copy link
@odow

odow Jan 18, 2024

Author Member

This can happen though. There are many orders that satisfy the reverse pass property, which is all we really care about.

If the expression is +(*(2, x), *(3, y)), then the graph is

       +
    /     \
   *       *
  / \     / \
2.0  x  3.0  y

A BFS order is

      1
   /     \
  2       3
 / \     / \
4   5   6   7

a DFS order is

      1
   /     \
  2       5
 / \     / \
3   4   6   7

and this arbitrary order also works

      1
   /     \
  2       4
 / \     / \
3   6   5   7
* The arguments for a `CALL` node are ordered in the tape based on the order in
which they appear in the function call.

#### Design goals

This is less readable than the other options, but does this data structure meet
our design goals?

Expand All @@ -524,9 +536,6 @@ easy to identify the _parent_ of any node. Therefore, we can use
[`Nonlinear.adjacency_matrix`](@ref) to compute a sparse matrix that maps
parents to their children.

The tape is also ordered topologically, so that a reverse pass of the nodes
evaluates all children nodes before their parent.

### The design in practice

In practice, `Node` and `Expression` are exactly [`Nonlinear.Node`](@ref)
Expand Down

0 comments on commit 57f09df

Please sign in to comment.