private static ImmutableArray <BoundDecisionDagNode> ShortestPathToNode( ImmutableArray <BoundDecisionDagNode> nodes, BoundDecisionDagNode node, bool nullPaths, out bool requiresFalseWhenClause) { // compute the distance from each node to the endpoint. var dist = PooledDictionary <BoundDecisionDagNode, (int distance, BoundDecisionDagNode next)> .GetInstance(); int nodeCount = nodes.Length; int infinity = 2 * nodeCount + 2; int distance(BoundDecisionDagNode x) { if (x == null) { return(infinity); } if (dist.TryGetValue(x, out var v)) { return(v.distance); } Debug.Assert(!nodes.Contains(x)); return(infinity); } for (int i = nodeCount - 1; i >= 0; i--) { var n = nodes[i]; dist.Add(n, n switch { BoundEvaluationDecisionDagNode e => (distance(e.Next), e.Next), BoundTestDecisionDagNode { Test: BoundDagNonNullTest _ } t when !nullPaths => (1 + distance(t.WhenTrue), t.WhenTrue), BoundTestDecisionDagNode { Test: BoundDagExplicitNullTest _ } t when !nullPaths => (1 + distance(t.WhenFalse), t.WhenFalse), BoundTestDecisionDagNode t when distance(t.WhenTrue) is var trueDist1 && distance(t.WhenFalse) is var falseDist1 => (trueDist1 <= falseDist1) ? (1 + trueDist1, t.WhenTrue) : (1 + falseDist1, t.WhenFalse), BoundWhenDecisionDagNode w when distance(w.WhenTrue) is var trueDist2 && distance(w.WhenFalse) is var falseDist2 => // add nodeCount to the distance if we need to flag that the path requires failure of a when clause (trueDist2 <= falseDist2) ? (1 + trueDist2, w.WhenTrue) : (1 + (falseDist2 < nodeCount ? nodeCount : 0) + falseDist2, w.WhenFalse), // treat the endpoint as distance 1. // treat other nodes as not on the path to the endpoint _ => ((n == node) ? 1 : infinity, null), });
/// <summary> /// Find the shortest path from the root node to the node of interest. /// </summary> /// <param name="nodes">The set of nodes in topological order.</param> /// <param name="node">The node of interest.</param> /// <param name="nullPaths">Whether to permit following paths that test for null.</param> /// <returns>The shortest path, excluding the node of interest.</returns> private static ImmutableArray <BoundDecisionDagNode> ShortestPathToNode( ImmutableArray <BoundDecisionDagNode> nodes, BoundDecisionDagNode node, bool nullPaths) { // compute the distance from each node to the endpoint. var dist = PooledDictionary <BoundDecisionDagNode, (int distance, BoundDecisionDagNode next)> .GetInstance(); int nodeCount = nodes.Length; int distance(BoundDecisionDagNode x) { if (x == null) { return(nodeCount + 2); } if (dist.TryGetValue(x, out var v)) { return(v.distance); } Debug.Assert(!nodes.Contains(x)); return(nodeCount + 2); } for (int i = nodeCount - 1; i >= 0; i--) { var n = nodes[i]; dist.Add(n, n switch { BoundEvaluationDecisionDagNode e => (distance(e.Next), e.Next), BoundTestDecisionDagNode { Test: BoundDagNonNullTest _ } t when !nullPaths => (1 + distance(t.WhenTrue), t.WhenTrue), BoundTestDecisionDagNode { Test: BoundDagExplicitNullTest _ } t when !nullPaths => (1 + distance(t.WhenFalse), t.WhenFalse), BoundTestDecisionDagNode t when distance(t.WhenTrue) is var trueDist && distance(t.WhenFalse) is var falseDist => (trueDist <= falseDist) ? (1 + trueDist, t.WhenTrue) : (1 + falseDist, t.WhenFalse), BoundWhenDecisionDagNode w when distance(w.WhenTrue) is var trueDist && distance(w.WhenFalse) is var falseDist => (trueDist <= falseDist) ? (1 + trueDist, w.WhenTrue) : (1 + falseDist, w.WhenFalse), // treat the endpoint as distance 1. // treat other nodes as not on the path to the endpoint _ => ((n == node) ? 1 : nodeCount + 2, null), });