< Summary

Information
Class: MoreStructures.SuffixStructures.Conversions.FullyIterativeConverter
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/SuffixStructures/Conversions/FullyIterativeConverter.cs
Line coverage
100%
Covered lines: 74
Uncovered lines: 0
Coverable lines: 74
Total lines: 148
Line coverage: 100%
Branch coverage
100%
Covered branches: 32
Total branches: 32
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
TrieToTree(...)100%2100%
get_TreeNodeChildrenMaybe()100%1100%
get_TreeNodeParentChildren()100%1100%
get_TreeEdge()100%1100%
get_TrieNode()100%1100%
ProcessTrieToTreeStack(...)100%14100%
get_TrieNodeChildrenMaybe()100%1100%
get_TreeEdge()100%1100%
get_TreeNode()100%1100%
get_ParentChildren()100%1100%
TreeToTrie(...)100%2100%
ProcessTreeToTrieStack(...)100%14100%

File(s)

/home/runner/work/MoreStructures/MoreStructures/MoreStructures/SuffixStructures/Conversions/FullyIterativeConverter.cs

#LineLine coverage
 1using MoreStructures.SuffixTrees;
 2using MoreStructures.SuffixTries;
 3
 4namespace MoreStructures.SuffixStructures.Conversions;
 5
 6using static ConverterHelpers;
 7
 8/// <summary>
 9/// <inheritdoc cref="IConverter"/>
 10/// </summary>
 11/// <remarks>
 12///     <para id="advantages">
 13///     ADVANTAGES AND DISADVANTAGES
 14///     <br/>
 15///     Conversion is done iteratively both for branching and no-branching paths (i.e. on nodes having a single child)
 16///     of the input <see cref="SuffixTrieNode"/>, with occasional mutation of internal state of the conversion and the
 17///     use of a stack to store nodes to process.
 18///     <br/>
 19///     Not limited by call stack depth.
 20///     <br/>
 21///     Convenient with deep trees (i.e. trees having a height &gt; ~1K nodes).
 22///     </para>
 23/// </remarks>
 24public class FullyIterativeConverter : IConverter
 25{
 26    /// <inheritdoc path="//*[not(self::summary or self::remarks)]"/>
 27    /// <summary>
 28    ///     <inheritdoc/>
 29    /// </summary>
 30    /// <remarks>
 31    ///     <inheritdoc cref="FullyIterativeConverter" path="/remarks"/>
 32    ///     <inheritdoc cref="IConverter.TrieToTree(SuffixTrieNode)" path="/remarks"/>
 33    /// </remarks>
 34    public SuffixTreeNode TrieToTree(SuffixTrieNode trieNode)
 1435    {
 1436        var stack = new Stack<StackFrameTrieToTree>();
 1437        var dictionaryToRoot = new Dictionary<SuffixTreeEdge, SuffixTreeNode>() { };
 1438        var edgeToRoot = new SuffixTreeEdge(0, 1);
 1439        stack.Push(new StackFrameTrieToTree(null, dictionaryToRoot, edgeToRoot, trieNode));
 40
 3006441        while (stack.Count > 0)
 3005242            ProcessTrieToTreeStack(stack);
 43
 1244        return dictionaryToRoot[edgeToRoot];
 1245    }
 46
 47    private record struct StackFrameTrieToTree(
 48        // Non-null on second pass only, when children have already been processed (done only for intermediate nodes)
 6010649        IDictionary<SuffixTreeEdge, SuffixTreeNode>? TreeNodeChildrenMaybe,
 6010650        IDictionary<SuffixTreeEdge, SuffixTreeNode> TreeNodeParentChildren,
 6010651        SuffixTreeEdge TreeEdge,
 6010652        SuffixTrieNode TrieNode);
 53
 54    private static void ProcessTrieToTreeStack(Stack<StackFrameTrieToTree> stack)
 3005255    {
 3005256        var (treeNodeChildrenMaybe, treeNodeParentChildren, treeEdge, trieNode) = stack.Pop();
 57
 3005258        if (trieNode is SuffixTrieNode.Leaf(var leafStart))
 1001959        {
 1001960            treeNodeParentChildren[treeEdge] = new SuffixTreeNode.Leaf(leafStart);
 1001961            return;
 62        }
 63
 2003364        if (trieNode is SuffixTrieNode.Intermediate(var trieNodeChildren))
 2003265        {
 2003266            if (treeNodeChildrenMaybe is IDictionary<SuffixTreeEdge, SuffixTreeNode> treeNodeChildren)
 1001567            {
 1001568                treeNodeParentChildren[treeEdge] = new SuffixTreeNode.Intermediate(treeNodeChildren);
 1001569            }
 70            else
 1001771            {
 1001772                treeNodeChildren = new Dictionary<SuffixTreeEdge, SuffixTreeNode> { };
 73
 1001774                stack.Push(new StackFrameTrieToTree(treeNodeChildren, treeNodeParentChildren, treeEdge, trieNode));
 75
 7009876                foreach (var (trieChildEdge, trieChildNode) in trieNodeChildren)
 2002477                {
 2002478                    var (coalescedChildEdge, coalescedChildNode) = IterativeCoalesce(trieChildEdge, trieChildNode);
 2002379                    stack.Push(new StackFrameTrieToTree(null, treeNodeChildren, coalescedChildEdge, coalescedChildNode))
 2002380                }
 1001681            }
 82
 2003183            return;
 84        }
 85
 186        throw new NotSupportedException($"{trieNode} of type {trieNode.GetType().Name} not supported");
 3005087    }
 88
 89    private record struct StackFrameTreeToTrie(
 90        // Non-null on second pass only, when children have already been processed (done only for intermediate nodes)
 10891        IDictionary<SuffixTrieEdge, SuffixTrieNode>? TrieNodeChildrenMaybe,
 10892        SuffixTreeEdge TreeEdge,
 10893        SuffixTreeNode TreeNode,
 10894        IDictionary<SuffixTrieEdge, SuffixTrieNode> ParentChildren);
 95
 96    /// <inheritdoc path="//*[not(self::summary or self::remarks)]"/>
 97    /// <summary>
 98    ///     <inheritdoc/>
 99    /// </summary>
 100    /// <remarks>
 101    ///     <inheritdoc cref="FullyIterativeConverter" path="/remarks"/>
 102    ///     <inheritdoc cref="IConverter.TreeToTrie(SuffixTreeNode)" path="/remarks"/>
 103    /// </remarks>
 104    public SuffixTrieNode TreeToTrie(SuffixTreeNode treeNode)
 13105    {
 13106        var stack = new Stack<StackFrameTreeToTrie>();
 13107        var edgeToRoot = new SuffixTrieEdge(0);
 13108        var parentChildren = new Dictionary<SuffixTrieEdge, SuffixTrieNode> { };
 13109        stack.Push(new(null, edgeToRoot, treeNode, parentChildren));
 64110        while (stack.Count > 0)
 53111            ProcessTreeToTrieStack(stack);
 112
 11113        return parentChildren[edgeToRoot];
 11114    }
 115
 116    private static void ProcessTreeToTrieStack(Stack<StackFrameTreeToTrie> stack)
 53117    {
 53118        var (trieNodeChildrenMaybe, treeEdge, treeNode, parentChildren) = stack.Pop();
 119
 53120        if (treeNode is SuffixTreeNode.Leaf(var leafStart))
 19121        {
 19122            var (expandedTrieEdge, expandedTrieNode) = IterativeExpand(treeEdge, new SuffixTrieNode.Leaf(leafStart));
 19123            parentChildren[expandedTrieEdge] = expandedTrieNode;
 19124            return;
 125        }
 126
 34127        if (treeNode is SuffixTreeNode.Intermediate(var treeNodeChildren))
 32128        {
 32129            if (trieNodeChildrenMaybe is IDictionary<SuffixTrieEdge, SuffixTrieNode> trieNodeChildren)
 15130            {
 15131                var (expandedTrieEdge, expandedTrieNode) = IterativeExpand(
 15132                   treeEdge, new SuffixTrieNode.Intermediate(trieNodeChildren));
 15133                parentChildren[expandedTrieEdge] = expandedTrieNode;
 15134            }
 135            else
 17136            {
 17137                trieNodeChildren = new Dictionary<SuffixTrieEdge, SuffixTrieNode> { };
 17138                stack.Push(new(trieNodeChildren, treeEdge, treeNode, parentChildren));
 101139                foreach (var child in treeNodeChildren)
 25140                    stack.Push(new(null, child.Key, child.Value, trieNodeChildren));
 17141            }
 142
 32143            return;
 144        }
 145
 2146        throw new NotSupportedException($"{treeNode} of type {treeNode.GetType().Name} not supported");
 51147    }
 148}