Use recursive dependency evaluation with memoization. After an edit, invalidate all cell states. To evaluate one formula, recursively obtain its dependencies before storing its own result. This is a depth-first search of the dependency graph; a visiting mark identifies a cycle, and a done mark avoids repeated evaluation of a shared dependency. The following single class implements the design, with public nested interfaces for formula extensions:
public final class Spreadsheet {
    public enum Kind { EMPTY, LABEL, NUMBER, FORMULA }

    public interface Lookup {
        double valueAt(int row, int col);
    }
    public interface Formula {
        double evaluate(Lookup values, int row, int col);
    }
    public static final class AddFormula implements Formula {
        private final int dr1, dc1, dr2, dc2;
        public AddFormula(int dr1, int dc1, int dr2, int dc2) {
            this.dr1 = dr1; this.dc1 = dc1;
            this.dr2 = dr2; this.dc2 = dc2;
        }
        public double evaluate(Lookup values, int r, int c) {
            return values.valueAt(r + dr1, c + dc1)
                 + values.valueAt(r + dr2, c + dc2);
        }
    }
    private static final class Cell {
        private final Kind kind;
        private final String label;
        private final double number;
        private final Formula formula;
        private Cell(Kind k, String s, double n, Formula f) {
            kind = k; label = s; number = n; formula = f;
        }
    }
    private static final Cell EMPTY =
        new Cell(Kind.EMPTY, null, 0.0, null);
    private final int rows, cols;
    private final Cell[][] cells;
    private final double[][] cache;
    private final byte[][] state;
    private final Lookup view = new Lookup() {
        public double valueAt(int r, int c) {
            return Spreadsheet.this.valueAt(r, c);
        }
    };

    public Spreadsheet(int rows, int cols) {
        if (rows < 0 || cols < 0) throw new IllegalArgumentException();
        this.rows = rows; this.cols = cols;
        cells = new Cell[rows][cols];
        cache = new double[rows][cols];
        state = new byte[rows][cols];
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < cols; c++) cells[r][c] = EMPTY;
    }
    private boolean inside(int r, int c) {
        return r >= 0 && r < rows && c >= 0 && c < cols;
    }
    private void check(int r, int c) {
        if (!inside(r, c)) throw new IndexOutOfBoundsException();
    }
    private void invalidate() {
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < cols; c++) state[r][c] = 0;
    }
    private void put(int r, int c, Cell cell) {
        check(r, c); cells[r][c] = cell; invalidate();
    }
    public void setEmpty(int r, int c) { put(r, c, EMPTY); }
    public void setLabel(int r, int c, String text) {
        if (text == null) throw new IllegalArgumentException();
        put(r, c, new Cell(Kind.LABEL, text, 0.0, null));
    }
    public void setNumber(int r, int c, double x) {
        put(r, c, new Cell(Kind.NUMBER, null, x, null));
    }
    public void setFormula(int r, int c, Formula f) {
        if (f == null) throw new IllegalArgumentException();
        put(r, c, new Cell(Kind.FORMULA, null, 0.0, f));
    }
    public Kind kindAt(int r, int c) {
        check(r, c); return cells[r][c].kind;
    }
    public String labelAt(int r, int c) {
        check(r, c); return cells[r][c].label;
    }
    public double valueAt(int r, int c) {
        if (!inside(r, c)) return 0.0;
        if (state[r][c] == 2) return cache[r][c];
        if (state[r][c] == 1)
            throw new IllegalStateException("Cyclic formula dependency");
        state[r][c] = 1;
        try {
            Cell cell = cells[r][c];
            double answer;
            switch (cell.kind) {
            case NUMBER: answer = cell.number; break;
            case FORMULA: answer = cell.formula.evaluate(view, r, c); break;
            default: answer = 0.0;
            }
            cache[r][c] = answer;
            state[r][c] = 2;
            return answer;
        } catch (RuntimeException error) {
            state[r][c] = 0;
            throw error;
        }
    }
    public void recalculate() {
        invalidate();
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < cols; c++) valueAt(r, c);
    }
}
The outer loop's order need not be a topological ordering, since recursion evaluates dependencies first. After an edit, callers can invoke recalculate; ordinary valueAt calls also calculate lazily from the invalidated state. Empty and label cells contribute zero without destroying their display content. Relative references are interpreted at the formula's location, and off-grid references contribute zero as required.
For an acyclic graph, mathematical induction over a topological ordering proves that each cached value equals the evaluation of current cell contents. Each cell becomes done at most once in a pass, so the time complexity is for cells and dependency references, plus formula arithmetic. The stack depth is at most the longest dependency path. A more elaborate implementation can record reverse dependencies and invalidate only cells affected by an edit.
The PDF gives no policy for circular formulas. Repeated numerical sweeps are not a general solution: a cell defined as itself plus one has no finite value, while a cell defined as itself plus zero has no unique value. The implementation therefore reports a cycle instead of looping or presenting an arbitrary stale value. An acyclic dependency graph is evaluated once per cell; circular dependencies are detected and rejected.
The AND-NOT circuit value problem belongs to P: validate the Boolean circuit and evaluate its gates in a topological ordering. Evaluation takes polynomial time even if its description is not already in a topological ordering.
For P-completeness we use logspace many-one reductions. Start from the supplied circuit value problem over the usual AND (logical conjunction), OR (logical disjunction) and NOT (negation) basis. Retain AND and NOT gates, and replace every OR gate by the De Morgan's laws gadget
This adds only a constant number of gates per old gate, preserves its truth value for all inputs and keeps the Boolean circuit acyclic. If the format includes constant source nodes, replace them by additional input nodes assigned fixed bits zero and one; these are inputs, not disallowed gates. Larger fan-in gates can first be replaced by binary trees of their inputs.
To output the new description, keep the old gate index and a constant-size gadget position, rescan old references when necessary, and assign consistent new indices to each gadget's terminal output. These counters and references occupy bits; the input assignment is copied with any constant-source bits appended. Thus the construction is a logspace many-one reduction preserving acceptance. Since Boolean circuit Value is P-complete under such reductions,
The global Markov property for a directed acyclic graph requires, for all pairwise disjoint vertex sets , that D-separation of and by in implies . Two Markov equivalent directed acyclic graphs encode exactly the same such D-separations. The structural characterization is that they have the same skeleton of a directed graph and the same unshielded colliders. A distribution has faithfulness of a directed acyclic graph when its conditional independences are exactly those encoded by D-separation; this includes the global Markov implication as well as its converse.
The population PC algorithm uses an exact conditional independence oracle. Start with the complete undirected graph, and conditioning-set size . At each size, examine ordered adjacent pairs . Test subsets of size until independence is found or all such subsets have been examined. On finding it, delete and record a symmetric separating set . Ordered pairs ensure that subsets from either endpoint's neighbours are considered. Increase until no adjacent ordered pair has enough remaining neighbours to supply a set of that size. Rechecking eligibility after deletion, or freezing the neighbours at each level and then deleting, gives the same population skeleton under the hypothesis below.
Next, for each unshielded triple with nonadjacent, orient precisely when . Propagate directions that are forced without introducing a directed cycle or an additional unshielded collider. In particular, with nonadjacent forces ; an undirected edge with a directed path from to forces ; and with nonadjacent forces . The first avoids a new unshielded collider, the second a directed cycle. For the third, would force and to avoid cycles, creating the prohibited unshielded collider .
For a fully specified exact completion, list all acyclic orientations of the recovered skeleton which extend the collider arrows and have exactly the recorded unshielded colliders. Direct an edge if and only if all listed graphs orient it the same way; otherwise leave it undirected. This finite enumeration implements the definition of the completed partially directed acyclic graph; orientation propagation is the usual efficient way to obtain the same completion. The equivalence-class proof below uses the exact completion description and does not need an unproved completeness claim about a chosen subset of propagation rules.
To prove correctness, assume faithfulness of a directed acyclic graph to . A true edge cannot be D-separated by any set excluding its endpoints: its length-one path is always active. Thus a true edge is never deleted. Conversely, take nonadjacent and choose their order so that is earlier than in a topological ordering of . Then is a nondescendant and nonparent of . Its parent set gives D-separation of and . To see this local graphical fact, a path beginning is blocked by the conditioned parent , a noncollider. A path beginning with an arrow out of must encounter a first collider before reaching the nondescendant . That collider is a descendant of , and neither it nor any of its descendants can be a parent of in an acyclic graph. Hence conditioning on does not open it.
All parent edges survive. If has not already been deleted, remains among 's neighbours excluding . It is therefore tested by size , and faithfulness forces deletion. The size loop cannot stop prematurely while this set remains eligible. This proves exact recovery of the skeleton of a directed graph.
For an unshielded triple , if it is a noncollider in , its length-two path remains active unless is conditioned on. Thus every separator of contains . If it is a collider, conditioning on opens the length-two path, so no separator can contain . Faithfulness turns these graphical statements into the recorded separator test. Therefore the collider phase recovers precisely all unshielded colliders. By the skeleton and collider characterization of Markov equivalence, the acyclic extensions with exactly these colliders are exactly the Markov equivalence of directed acyclic graphs class of . In particular that set is nonempty, and the completion returns its CPDAG. This proves population PC correctness under faithfulness.
For the four-variable example, the only removable pairs are , with separator , and , with separator . The remaining skeleton has edges . The unshielded triples and both have center outside the separator of , so both are unshielded colliders. Every remaining edge is thereby oriented:
The other two unshielded triples are noncolliders, consistent with the separator of . There is no undirected edge left, so the equivalence class consists of this unique Directed acyclic graph. This identification is about the given faithful observational distribution; general PC algorithm outputs need not identify a unique causal direction.
The moral graph of a Directed acyclic graph is formed by joining any two parents of a common child and then removing the directions from all edges. For D-separation, a path in the underlying undirected graph is active given when every noncollider on it is outside , and every collider has itself or a descendant in . Disjoint vertex sets and are D-separated by if no such active path connects them.
The adjacency characterization is
A one-edge path cannot be blocked by conditioning on other vertices. For a nonadjacent pair, choose the later vertex in a topological ordering. The earlier vertex is a nondescendant and is not a parent of , so the parents of separate the pair by the local Markov property of a directed acyclic graph.
Use faithfulness of a directed acyclic graph to mean that graphical and probabilistic independences agree, for all disjoint sets:
This includes the global Markov property of a directed acyclic graph as well as the absence of extra independences. The conditional independence graph of is the undirected graph in which is absent exactly when .
To identify this graph, condition on every vertex other than . Any noncollider in the interior of a path is then conditioned on, so an active path must have only colliders internally. Two adjacent interior vertices cannot both be colliders: the arrow joining them has an arrowhead at only one of its ends. Thus an active path can have no interior vertex, giving a direct edge, or just one, giving . In the latter case the conditioned common child activates the path. These possibilities are exactly the edges added or retained by moralization. Faithfulness therefore proves
This is why the moral graph equals the conditional independence graph under faithfulness.
For Gaussian graph estimation, collect the data into an matrix and let . The precision matrix has precisely for absent graph edges, by Gaussian conditional independence. In neighbourhood selection, fit a Lasso regression of each column on the others:
Select the nonzero coefficients as neighbours of , then make the graph undirected using either the OR rule, retaining an edge selected in at least one regression, or the AND rule, requiring both. These are instances of Nodewise Lasso.
The Graphical Lasso estimates the whole precision matrix jointly, for example by
Read off its nonzero off-diagonal entries as graph edges. This expression uses an off-diagonal penalty; an all-entry penalty is another convention.
To reduce computation in the PC algorithm, start its skeleton search from an estimate of the conditional independence graph rather than the complete graph. The exact graph contains the true DAG skeleton, so oracle tests can remove its extra edges while retaining the true adjacencies. Fewer initial edges and smaller neighbourhoods reduce both candidate pairs and candidate conditioning sets.
For correctness of the orientation stage, preserve valid separating-set records. With an exact conditional independence graph, an initially absent pair has the full complement as a separating set. Record that set, and record the usual discovered sets for edges removed later. Leaving an initially absent pair with an empty default could falsely mark an unshielded noncollider as a collider. This describes PC initialization from a conditional independence graph; with an estimated initial graph, screening errors can propagate into the output.
A procedure controls the familywise error rate at level when, for every configuration of true nulls ,
Let . The step-down procedure can reject any true null only if it reaches and rejects , which requires . Since a valid p-value under its null satisfies , the procedure controls FWER without any assumption on dependence among the p-values.
A distribution has the global Markov property for a directed acyclic graph when every D-separation statement implies the corresponding conditional independence under .
If has nonadjacent vertices , choose a topological ordering. Suppose precedes . Then is a non-descendant and non-parent of , so the directed local Markov property gives
The reversed ordering case is analogous. Hence
Use the intersection-union test: reject exactly when for every . Under , at least one is true, so
This is nontrivial because it rejects whenever every tested conditional independence is rejected.
Choose the given topological ordering. Since precedes , is not a descendant of ; since they are nonadjacent, it is not a parent of . The local Markov property of a directed acyclic graph says that a node is d-separated from all its nondescendants other than its parents by its parent set. Therefore and are d-separated by .
It follows that adjacency of is certified by rejecting every null hypothesis
If the vertices were nonadjacent, the theorem would supply one such separating parent set, whichever vertex comes later.
To certify that is a parent of , first reject
for every , which forces adjacency. Then reject
for every such . If the adjacent edge were , then would orient as a collider, and the parent-set argument would provide a separator not containing , contradicting the second collection of rejections. Hence the edge is .
With an exact conditional independence oracle and faithfulness of a directed acyclic graph, the skeleton phase of the PC algorithm deletes precisely the nonedges. A true edge cannot be D-separated by a set excluding its endpoints. For nonadjacent vertices, choose the later vertex in a topological ordering; its parents separate it from the earlier nonparent. True parent edges survive throughout, so this separator remains available among the algorithm's candidate neighbour sets. For an unshielded triple , any recorded separator of excludes exactly when the triple is an unshielded collider. The skeleton and collider characterization of Markov equivalence therefore identifies the correct equivalence class. Directions compelled throughout that class give its completed partially directed acyclic graph.
Spreadsheet dependency evaluation Created 2026-10-13 Updated 2026-10-14
Evaluate numeric formula dependencies using depth-first search and memoization, or a topological ordering. Marking active evaluations detects cycles; repeated numerical sweeps need not terminate or determine a unique result.
A spreadsheet dependency graph turns a page of spreadsheet formulas into a plan: compute each prerequisite before the spreadsheet cell that consumes it. This section uses a deliberately small model with explicit cell references, fixed spreadsheet formulas, and deterministic computation from numerical inputs. There are no external data changes or formulas that change their references while running. Within these assumptions, a topological order gives a reproducible answer without repeatedly sweeping the visible grid.
Take two input spreadsheet cells and five spreadsheet formulas:
Spreadsheet cellStored input or spreadsheet formulaInitial valueValue after changing A1 to 5
A13, later 5
A24
B1=A1+A2
B2=2*A1
C1=B1+B2
D1=C1/2
E1=A2^2
Figure 1.
An original spreadsheet dependency graph and a topological order with values before and after one edit
. Details.
Our directed edge convention is prerequisite to consumer: A1 B1 means that B1 reads A1, not the reverse. The seven directed edges are A1 B1, A2 B1, A1 B2, B1 C1, B2 C1, C1 D1, and A2 E1. This spreadsheet dependency graph is a Directed acyclic graph. One topological order is A1,A2,B1,B2,C1,D1,E1; E1 could instead be computed immediately after A2. A topological order constrains prerequisites, not the physical positions of spreadsheet cells.
In that order, the initial arithmetic operations give , , , , and . The spreadsheet formulas define one value per spreadsheet cell: an outline by induction along any topological order shows that every prerequisite already has its uniquely determined value when its consumer is computed. Different permitted orders therefore agree in this model. The useful idea is that information flows through the Directed acyclic graph even when the visible grid does not display that flow.
A concrete implementation history illustrates this separation. Microsoft's documentation distinguishes the per-worksheet calculation chains used in Excel 2002 and earlier from calculation using multiple software threads introduced in Excel 2007 for independent chain sections. This is a documented implementation example, not a definition of spreadsheet dependency evaluation.[ref]
Topological order 2026-10-14
A topological order of a finite directed graph is a sequence containing every vertex exactly once, with
Thus every directed edge points forward in the list. Equivalently, a bijection assigning positions satisfies for every directed edge . A topological ordering names the same kind of list. [ref]
The toy Directed acyclic graph has exactly five topological orders: , , , , and . These lists were checked by enumerating all permutations and retaining precisely those satisfying all five directed edge inequalities. Every list ends with , since all other tasks have a directed path to publication. A topological order need not put adjacent entries next to one another in the directed graph: and are consecutive in without a directed edge between them.
A directed cycle would force the impossible chain of position inequalities . In the toy example, adding requires review before publication and publication before review, so there are no topological orders. Together with the construction in topological sorting, this proves that a finite directed graph admits a topological order if and only if it is a Directed acyclic graph. The empty directed graph has the empty sequence as its topological order.
There is also a useful connection to partial orders: define when or there is a directed path from to . For a Directed acyclic graph, this reachability relation is a partial order, and its linear extensions are exactly the topological orders. The Directed acyclic graph specifies which pairs must be ordered; a topological order chooses positions for all the remaining pairs.
Topological ordering Created 2026-09-24 Updated 2026-10-14
A topological ordering is a topological order: a list containing every vertex once and placing the source of every directed edge before its destination. In the parent-and-child language of a Directed acyclic graph, every parent precedes every child, and hence every ancestor precedes every descendant along a directed path. This is an ordering of the vertices, whereas topological sorting is the task of finding it. See topological order for the precise position condition and Kahn's algorithm for a construction.