Exemplo n.º 1
0
            /// <summary>
            /// Follows all paths leaving a node and returns the first one that has a reference genome location.
            /// </summary>
            /// <param name="node"></param>
            /// <param name="grabRightSide"></param>
            /// <param name="curDistance">How far removed from node we are at present</param>
            /// <returns></returns>
            private DistanceLocation FollowNode(DeBruijnNode node, bool grabRightSide, int curDistance)
            {
                var nextNodes =
                    grabRightSide ? node.GetRightExtensionNodesWithOrientation() : node.GetLeftExtensionNodesWithOrientation();

                foreach (var neighbor in nextNodes)
                {
                    if (neighbor.Key.IsInReference)
                    {
                        return(new DistanceLocation()
                        {
                            Distance = curDistance, RefGenomeLocation = neighbor.Key.ReferenceGenomePosition
                        });
                    }
                    else
                    {
                        var nextSideRight = !(neighbor.Value ^ grabRightSide);
                        var res           = FollowNode(neighbor.Key, nextSideRight, curDistance + 1);
                        if (res != null)
                        {
                            return(res);
                        }
                    }
                }
                return(null);
            }
Exemplo n.º 2
0
        /// <summary>
        /// Trace simple path in specified direction.
        /// </summary>
        /// <param name="contigPath">List of graph nodes corresponding to contig path.</param>
        /// <param name="contigSequence">Sequence of contig being assembled.</param>
        /// <param name="isForwardDirection">Boolean indicating direction of path.</param>
        /// <param name="sameOrientation">Path orientation.</param>
        /// <param name="node">Next node on the path.</param>
        /// <param name="createContigSequences">Indicates whether the contig sequences are to be created or not.</param>
        private void TraceSimplePathLinks(
            List <DeBruijnNode> contigPath,
            List <byte> contigSequence,
            bool isForwardDirection,
            bool sameOrientation,
            DeBruijnNode node,
            bool createContigSequences)
        {
            bool endFound = false;

            while (!endFound)
            {
                node.IsVisited = true;
                // Get extensions going in same directions.
                Dictionary <DeBruijnNode, bool> sameDirectionExtensions = (isForwardDirection ^ sameOrientation)
                    ? node.GetLeftExtensionNodesWithOrientation()
                    : node.GetRightExtensionNodesWithOrientation();

                if (sameDirectionExtensions.Count == 0)
                {
                    // Found end of path. Add this and return
                    CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences);
                    endFound = true;
                }
                else
                {
                    var sameDirectionExtension = sameDirectionExtensions.First();

                    // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1)
                    // Continue traceback in the same direction. Add this node to list and continue.
                    if (!CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences))
                    {
                        // Loop is found. Cannot extend simple path further
                        //Assuming that any node with extensions >2 from either side have been trimmed, this should only be possible if the first
                        //node in list is last node as well, this means there is a circle in the graph of length >1, going to report it
                        if (contigPath != null && contigPath.Count > 0 && contigPath[0] == node)
                        {
                            endFound = true;
                        }
                    }
                    else
                    {
                        node            = sameDirectionExtension.Key;
                        sameOrientation =
                            !(sameOrientation ^ sameDirectionExtension.Value);
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Trace simple path starting from 'node' in specified direction.
        /// </summary>
        /// <param name="assembledContigs">List of assembled contigs.</param>
        /// <param name="node">Starting node of contig path.</param>
        /// <param name="isForwardDirection">Boolean indicating direction of path.</param>
        /// <param name="createContigSequences">Boolean indicating whether the contig sequences are to be created or not.</param>
        /// <param name="DuplicatesPossible">Boolean indicating if duplicates are possible, true if both the forward and reverse path could be generated</param>
        private void TraceSimplePath(List <ISequence> assembledContigs, DeBruijnNode node, bool isForwardDirection, bool createContigSequences, bool DuplicatesPossible)
        {
            ISequence   nodeSequence   = this._graph.GetNodeSequence(node);
            List <byte> contigSequence = new List <byte>(nodeSequence);

            node.IsVisited = true;
            List <DeBruijnNode> contigPath = new List <DeBruijnNode> {
                node
            };
            KeyValuePair <DeBruijnNode, bool> nextNode =
                isForwardDirection ? node.GetRightExtensionNodesWithOrientation().First() : node.GetLeftExtensionNodesWithOrientation().First();

            this.TraceSimplePathLinks(contigPath, contigSequence, isForwardDirection, nextNode.Value, nextNode.Key, createContigSequences);

            // Check to remove duplicates
            if (!DuplicatesPossible || contigPath[0].NodeValue.CompareTo(contigPath.Last().NodeValue) >= 0)
            {
                double coverage = contigPath.Average(n => n.KmerCount);
                // Check contig coverage.
                if (!Double.IsNaN(_coverageThreshold))
                {
                    // Definition from Velvet Manual: http://helix.nih.gov/Applications/velvet_manual.pdf
                    // "k-mer coverage" is how many times a k-mer has been seen among the reads.

                    if (coverage < this._coverageThreshold)
                    {
                        contigPath.ForEach(n => n.MarkNodeForDelete());
                        return;
                    }
                }
                else
                {
                    if (createContigSequences)
                    {
                        lock (assembledContigs)
                        {
                            var seq = new Sequence(nodeSequence.Alphabet, contigSequence.ToArray());
                            seq.ID = " Avg K-Mer Coverage = " + coverage.ToString();
                            assembledContigs.Add(seq);
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
 public IEnumerable <DeBruijnNode> GetNodesLeavingTop()
 {
     //if chain is longer than one, use previous node to get latest
     if (this.ConstituentNodes.Count > 1)
     {
         var          topNode     = ConstituentNodes[0];
         DeBruijnNode penUltimate = ConstituentNodes[1];
         bool         goingLeft   = penUltimate.GetLeftExtensionNodes().Contains(topNode);
         var          next        = goingLeft ? penUltimate.GetLeftExtensionNodesWithOrientation().Where(x => x.Key == topNode).First() :
                                    penUltimate.GetRightExtensionNodesWithOrientation().Where(x => x.Key == topNode).First();
         var nextSet = goingLeft ^ next.Value ? next.Key.GetRightExtensionNodes() :
                       next.Key.GetLeftExtensionNodes();
         foreach (var k in nextSet)
         {
             yield return(k);
         }
     }
     else
     {
         var baseNode = this.ConstituentNodes[0];
         Debug.Assert(KmerLength == Sequence.Length);
         var  ns = new Sequence(DnaAlphabet.Instance, baseNode.GetOriginalSymbols(MetaNode.KmerLength));
         bool orientationRight;    // = baseNode.GetOriginalSymbols(KmerLength).SequenceEqual(new DnaAlphabet(DnaAlphabet.Instance, Sequence));
         if (ns.ConvertToString().Equals(Sequence))
         {
             orientationRight = true;
         }
         else if ((new Sequence(ns.GetReverseComplementedSequence()).ConvertToString().Equals(Sequence)))
         {
             orientationRight = false;
         }
         else
         {
             throw new Exception("AAA");
         }
         var nextNodes = orientationRight ? baseNode.GetLeftExtensionNodes() : baseNode.GetRightExtensionNodes();
         foreach (var v in nextNodes)
         {
             yield return(v);
         }
     }
 }
Exemplo n.º 5
0
        /// <summary>
        /// Follow a node with one neighbor on either side and make sure it never reaches itself, which is problematic for making these things.
        /// Note that nodes can go to A->A->C if they refer to themselves but match the reverse compliment of themselves
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="goRight"></param>
        /// <param name="graph"></param>
        /// <returns></returns>
        private bool VerifyNotCircular(DeBruijnNode currentNode)
        {
            List <DeBruijnNode> visitedNodes = new List <DeBruijnNode>();

            if (ClassifyNode(currentNode) != NODE_TYPE.LINK_IN_CHAIN)
            {
                throw new Exception("Node type doesn't match well!");
            }
            else
            {
                //go right, if we wind up where we started, circle.
                var  nextNode   = currentNode.GetRightExtensionNodesWithOrientation().First();
                bool goingRight = true;
                //we now either have the second or third node in path as next
                while (ClassifyNode(nextNode.Key) == NODE_TYPE.LINK_IN_CHAIN)
                {
                    visitedNodes.Add(nextNode.Key);
                    //determine if this is a kink or not, which will trigger issue at only first node.
                    if (nextNode.Key == currentNode)
                    {
                        //only one way to get back to the start, either we are in a circle, or the first node loops in to its reverse compliment and exits
                        //the other way, a "kink" so to speak, we know we have visited the right node since we started there, if we visited the left, problems
                        bool leftVisited = visitedNodes.Contains(currentNode.GetLeftExtensionNodes().First());
                        if (leftVisited)
                        {
                            return(false);
                        }
                        Debug.Assert(visitedNodes.Contains(currentNode.GetRightExtensionNodes().First()));
                    }

                    goingRight = !(goingRight ^ nextNode.Value);
                    var nextSet = goingRight ? nextNode.Key.GetRightExtensionNodesWithOrientation() : nextNode.Key.GetLeftExtensionNodesWithOrientation();
                    if (nextSet.Count != 1)
                    {
                        return(true);
                    }
                    nextNode = nextSet.First();
                }
                return(true);
            }
        }
Exemplo n.º 6
0
        private void MakeCircle(DeBruijnNode startNode, DeBruijnGraph graph)
        {
            CircularLoop = true;
            byte[] v = startNode.GetOriginalSymbols(graph.KmerLength);
            Console.WriteLine((new Sequence(DnaAlphabet.Instance, v)).ToString());
            ConstituentNodes.Add(startNode);
            startNode.IsVisited = true;
            Dictionary <DeBruijnNode, bool> nextNodes;
            bool goRight = true;

            nextNodes = startNode.GetRightExtensionNodesWithOrientation();
            var          nextSet = nextNodes.First();
            DeBruijnNode next    = nextSet.Key;

            while (next != startNode)
            {
                next.IsVisited = true;
                ConstituentNodes.Add(next);
                bool      sameOrientation = nextSet.Value;
                NODE_TYPE nextType        = ClassifyNode(next);
                //what direction do we get the node following the next one from? (Note path out determined by path in, so don't need to look at next node to get side of the one after).
                goRight = (!goRight) ^ sameOrientation;
                if (nextType == NODE_TYPE.LINK_IN_CHAIN)
                {
                    //NOTE: four possibilities condense in to 2 possible sides so written with ^ operator
                    nextNodes = goRight ? next.GetRightExtensionNodesWithOrientation() : next.GetLeftExtensionNodesWithOrientation();
                    //now how to determine what base to get? This only depends on relationship of current node to next node
                    //in all cases we either grab the RC of the first base or the last base, and which to grab is determined by incoming node
                    byte nextSymbol = GetNextSymbol(next, graph.KmerLength, !goRight);
                    contigSequence.Add(nextSymbol);
                }
                else
                {
                    throw new Exception("Non circular path being treated like one");
                }
                nextSet = nextNodes.First();
                next    = nextSet.Key;
            }
            Sequence = (new Sequence((IAlphabet)NoGapDnaAlphabet.Instance, contigSequence.ToArray())).ConvertToString(0, contigSequence.Count);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Follow a chain along a path link a bifurcation or no additional nodes appear.
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="goRight"></param>
        /// <param name="graph"></param>
        /// <returns></returns>
        private Dictionary <DeBruijnNode, bool> ExtendChain(DeBruijnNode currentNode, bool goRight, DeBruijnGraph graph)
        {
            ConstituentNodes.Add(currentNode);
            currentNode.IsVisited = true;
            Dictionary <DeBruijnNode, bool> nextNodes;

            if (goRight)
            {
                nextNodes = currentNode.GetRightExtensionNodesWithOrientation();
            }
            else
            {
                nextNodes = currentNode.GetLeftExtensionNodesWithOrientation();
            }
            DeBruijnNode next;
            DeBruijnNode last = currentNode;

            while (nextNodes.Count == 1)
            {
                var nextSet = nextNodes.First();
                next = nextSet.Key;
                bool sameOrientation = nextSet.Value;
                goRight = (!goRight) ^ sameOrientation;
                int oppositeDirectionExtensions = goRight ? next.LeftExtensionNodesCount : next.RightExtensionNodesCount;
                int sameDirectionExtensions     = goRight ? next.RightExtensionNodesCount : next.LeftExtensionNodesCount;
                Debug.Assert(oppositeDirectionExtensions != 0);//should always be >1 given the node we came from.
                if (oppositeDirectionExtensions > 1)
                {
                    break;//nexus, or need to start a new node, no visit count
                }
                else
                {
                    //we have to check if the right path loops back on itself, for example TTTTTTTTTTTT could keep adding T's to infinity, always going back to the same node.
                    //However, it is also possible that the node can refer to itself, but not in a loop, e.g. by turning around, like
                    //TTTTTTTCAATTGAAAAAA which matches the reverse compliment of itself, so leaves the other side (not this might be incorrect as this is guaranteed).
                    //unfortunately, impossible to tell without looking two steps into the future, and because we are doing this one at a time,
                    //have to unwind the last addition.
                    if (next.IsVisited)
                    {
                        //note that this is a bit of an unusual step, as most of the time the other direction extensions will be >1.  This can only
                        //happen if the only incoming node to this k-mer-1 palindrome does not have any other links, which will be rare.
                        if (next == last)
                        {
                            //if going to refer to itself again, it's a loop, need to end it and make a new self referencing mega node.
                            var temp = goRight ? next.GetRightExtensionNodesWithOrientation() : next.GetLeftExtensionNodesWithOrientation();
                            if (temp.Count == 1 && temp.First().Key == last)//three times in a row, need to remove this node from the list as we are not leaving in a different direction, //and need to unvisit the node
                            {
                                //unwind the last addition, this node needs to be a self-referencing mega node
                                next.IsVisited = false;
                                Debug.Assert(ConstituentNodes.Last() == next);
                                ConstituentNodes.RemoveAt(ConstituentNodes.Count - 1);
                                contigSequence.RemoveAt(ConstituentNodes.Count - 1);
                                Debug.Assert(ConstituentNodes.Last() != next);

                                //exit, we are as low as we can go.
                                break;
                            }
                            //criteria is that the sequence can't be there more than once
                        }
                        //At most a kmer can be used to represent the forward and reverse sequence that it has.
                        Debug.Assert(this.ConstituentNodes.Count(x => x == next) < 3);
                    }
                    byte nextSymbol = GetNextSymbol(next, graph.KmerLength, !goRight);
                    contigSequence.Add(nextSymbol);
                    //byte[] original=next.NodeValue.GetOriginalSymbols(MegaNode.KmerLength);
                    //var s=new Sequence(DnaAlphabet.Instance,original);
                    //Console.WriteLine(s.ConvertToString());

                    next.IsVisited = true;
                    ConstituentNodes.Add(next);
                    nextNodes = goRight ? next.GetRightExtensionNodesWithOrientation() : next.GetLeftExtensionNodesWithOrientation();
                    last      = next;
                }
            }

            return(nextNodes);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Trace simple path in specified direction.
        /// </summary>
        /// <param name="contigPath">List of graph nodes corresponding to contig path.</param>
        /// <param name="contigSequence">Sequence of contig being assembled.</param>
        /// <param name="isForwardDirection">Boolean indicating direction of path.</param>
        /// <param name="sameOrientation">Path orientation.</param>
        /// <param name="node">Next node on the path.</param>
        /// <param name="createContigSequences">Indicates whether the contig sequences are to be created or not.</param>
        private void TraceSimplePathLinks(
            IList <DeBruijnNode> contigPath,
            List <byte> contigSequence,
            bool isForwardDirection,
            bool sameOrientation,
            DeBruijnNode node,
            bool createContigSequences)
        {
            bool endFound = false;

            while (!endFound)
            {
                // Get extensions going in same directions.
                Dictionary <DeBruijnNode, bool> sameDirectionExtensions = (isForwardDirection ^ sameOrientation) ?
                                                                          node.GetLeftExtensionNodesWithOrientation() : node.GetRightExtensionNodesWithOrientation();

                if (sameDirectionExtensions.Count == 0)
                {
                    // Found end of path. Add this and return
                    this.CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences);
                    endFound = true;
                }
                else
                {
                    var sameDirectionExtension = sameDirectionExtensions.First();

                    // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1)
                    // Continue traceback in the same direction. Add this node to list and continue.
                    if (!this.CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences))
                    {
                        // Loop is found. Cannot extend simple path further
                        break;
                    }
                    else
                    {
                        node            = sameDirectionExtension.Key;
                        sameOrientation =
                            !(sameOrientation ^ sameDirectionExtension.Value);
                    }
                }
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Starting from potential end of dangling link, trace back along
        /// extension edges in graph to find if it is a valid dangling link.
        /// Parallelization Note: No locks used in TraceDanglingLink.
        /// We only read graph structure here. No modifications are made.
        /// </summary>
        /// <param name="isForwardDirection">Boolean indicating direction of dangling link.</param>
        /// <param name="link">Dangling Link.</param>
        /// <param name="node">Node that is next on the link.</param>
        /// <param name="sameOrientation">Orientation of link.</param>
        /// <returns>List of nodes in dangling link.</returns>
        private DeBruijnPath TraceDanglingExtensionLink(bool isForwardDirection, DeBruijnPath link, DeBruijnNode node, bool sameOrientation)
        {
            Dictionary <DeBruijnNode, bool> sameDirectionExtensions;
            int sameDirectionExtensionsCount;
            int oppDirectionExtensionsCount;

            bool reachedEndPoint = false;

            while (!reachedEndPoint)
            {
                // Get extensions going in same and opposite directions.
                if (isForwardDirection ^ sameOrientation)
                {
                    sameDirectionExtensionsCount = node.LeftExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.RightExtensionNodesCount;
                    sameDirectionExtensions      = node.GetLeftExtensionNodesWithOrientation();
                }
                else
                {
                    sameDirectionExtensionsCount = node.RightExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.LeftExtensionNodesCount;
                    sameDirectionExtensions      = node.GetRightExtensionNodesWithOrientation();
                }

                if (sameDirectionExtensionsCount == 0)
                {
                    // Found other end of dangling link
                    // Add this and return.
                    return(this.CheckAndAddDanglingNode(link, node, out reachedEndPoint));
                }
                else if (oppDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list without updating it.
                    if (this.erodeThreshold != -1 && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            this.danglingLinkExtensionTasks.Add(new Task <int>((o) => this.ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, false), TaskCreationOptions.None));
                        }

                        return(null);
                    }

                    return(link);
                }
                else if (sameDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list after updating it.
                    link = this.CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                    if (this.erodeThreshold != -1 && reachedEndPoint != true && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            this.danglingLinkExtensionTasks.Add(new Task <int>((o) => this.ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, true), TaskCreationOptions.None));
                        }

                        return(null);
                    }

                    return(link);
                }
                else
                {
                    // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1)
                    // Continue trace back. Add this node to that list and recurse.
                    link = this.CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                    if (reachedEndPoint)
                    {
                        // Loop is found or threshold length has been exceeded.
                        return(link);
                    }
                    else
                    {
                        var item = sameDirectionExtensions.First();
                        node            = item.Key;
                        sameOrientation = !(sameOrientation ^ item.Value);
                    }
                }
            }

            return(null); // code will never reach here. Valid returns happen within the while loop.
        }
Exemplo n.º 10
0
        /// <summary>
        /// Starting from potential end of dangling link, trace back along
        /// extension edges in graph to find if it is a valid dangling link.
        /// Parallelization Note: No locks used in TraceDanglingLink.
        /// We only read graph structure here. No modifications are made.
        /// </summary>
        /// <param name="isForwardDirection">Boolean indicating direction of dangling link.</param>
        /// <param name="link">Dangling Link.</param>
        /// <param name="node">Node that is next on the link.</param>
        /// <param name="sameOrientation">Orientation of link.</param>
        /// <returns>List of nodes in dangling link.</returns>
        private DeBruijnPath TraceDanglingExtensionLink(bool isForwardDirection, DeBruijnPath link, DeBruijnNode node, bool sameOrientation)
        {
            bool reachedEndPoint = false;

            while (!reachedEndPoint)
            {
                // Get extensions going in same and opposite directions.
                Dictionary <DeBruijnNode, bool> sameDirectionExtensions;
                int sameDirectionExtensionsCount;
                int oppDirectionExtensionsCount;
                if (isForwardDirection ^ sameOrientation)
                {
                    sameDirectionExtensionsCount = node.LeftExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.RightExtensionNodesCount;
                    //Avoid self references here and below
                    //TODO: We should force the k-mer to be large enough that there is no
                    sameDirectionExtensions = node.GetLeftExtensionNodesWithOrientation().
                                              Where(x => x.Key != node).
                                              ToDictionary(x => x.Key, y => y.Value);
                }
                else
                {
                    sameDirectionExtensionsCount = node.RightExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.LeftExtensionNodesCount;
                    sameDirectionExtensions      = node.GetRightExtensionNodesWithOrientation().
                                                   Where(x => x.Key != node).
                                                   ToDictionary(x => x.Key, y => y.Value);
                }

                if (sameDirectionExtensionsCount == 0)
                {
                    // Found other end of dangling link
                    // Add this and return.
                    return(this.CheckAndAddDanglingNode(link, node, out reachedEndPoint));
                }

                if (oppDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list without updating it.
                    if (this.erodeThreshold != -1 && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            //THis task essentially just returns back to this method after other ones are removed
                            this.danglingLinkExtensionTasks.Add(new Task <int>((o) => this.ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, false), TaskCreationOptions.None));
                        }

                        return(null);
                    }

                    return(link);
                }

                if (sameDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list after updating it.
                    link = this.CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                    if (this.erodeThreshold != -1 && reachedEndPoint != true && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            this.danglingLinkExtensionTasks.Add(new Task <int>((o) => this.ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, true), TaskCreationOptions.None));
                        }

                        return(null);
                    }

                    return(link);
                }

                // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1)
                // Continue trace back. Add this node to that list and recurse.
                link = this.CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                if (reachedEndPoint)
                {
                    // Loop is found or threshold length has been exceeded.
                    return(link);
                }

                //still in loop, so just add the extension and keeps going
                var item = sameDirectionExtensions.First();
                node            = item.Key;
                sameOrientation = !(sameOrientation ^ item.Value);
            }

            return(null); // code will never reach here. Valid returns happen within the while loop.
        }
Exemplo n.º 11
0
        /// <summary>
        /// Starting from potential end of dangling link, trace back along
        /// extension edges in graph to find if it is a valid dangling link.
        /// Parallelization Note: No locks used in TraceDanglingLink.
        /// We only read graph structure here. No modifications are made.
        /// </summary>
        /// <param name="isForwardDirection">Boolean indicating direction of dangling link.</param>
        /// <param name="link">Dangling Link.</param>
        /// <param name="node">Node that is next on the link.</param>
        /// <param name="sameOrientation">Orientation of link.</param>
        /// <returns>List of nodes in dangling link.</returns>
        private DeBruijnPath TraceDanglingExtensionLink(bool isForwardDirection, DeBruijnPath link, DeBruijnNode node, bool sameOrientation)
        {
            for (; ;)
            {
                // Get extensions going in same and opposite directions.
                Dictionary <DeBruijnNode, bool> sameDirectionExtensions;
                int sameDirectionExtensionsCount, oppDirectionExtensionsCount;

                if (isForwardDirection ^ sameOrientation)
                {
                    sameDirectionExtensionsCount = node.LeftExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.RightExtensionNodesCount;
                    sameDirectionExtensions      = node.GetLeftExtensionNodesWithOrientation();
                }
                else
                {
                    sameDirectionExtensionsCount = node.RightExtensionNodesCount;
                    oppDirectionExtensionsCount  = node.LeftExtensionNodesCount;
                    sameDirectionExtensions      = node.GetRightExtensionNodesWithOrientation();
                }

                bool reachedEndPoint;
                if (sameDirectionExtensionsCount == 0)
                {
                    // Found other end of dangling link
                    return(CheckAndAddDanglingNode(link, node, out reachedEndPoint));
                }

                if (oppDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list without updating it.
                    if (this.erodeThreshold != -1 && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            // This task essentially just returns back to this method after other ones are removed
                            this.danglingLinkExtensionTasks.Add(new Task <int>(_ =>
                                                                               ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, false), TaskCreationOptions.None));
                        }
                        return(null);
                    }
                    return(link);
                }

                if (sameDirectionExtensionsCount > 1)
                {
                    // Have reached a point of ambiguity. Return list after updating it.
                    link = CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                    if (this.erodeThreshold != -1 && reachedEndPoint != true && !node.IsMarkedForDelete)
                    {
                        lock (this.danglingLinkExtensionTasks)
                        {
                            this.danglingLinkExtensionTasks.Add(new Task <int>(_ =>
                                                                               ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, true), TaskCreationOptions.None));
                        }
                        return(null);
                    }
                    return(link);
                }

                // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1)
                // Continue trace back. Add this node to that list and recurse.
                link = CheckAndAddDanglingNode(link, node, out reachedEndPoint);
                if (reachedEndPoint)
                {
                    // Loop is found or threshold length has been exceeded.
                    return(link);
                }

                // Still in loop, so just add the extension and keeps going
                var item = sameDirectionExtensions.First();
                node            = item.Key;
                sameOrientation = !(sameOrientation ^ item.Value);
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Traces diverging paths in given direction.
        /// For each path in the set of diverging paths, extend path by one node
        /// at a time. Continue this until all diverging paths converge to a
        /// single node or length threshold is exceeded.
        /// If paths converge, add path cluster containing list of redundant
        /// path nodes to list of redundant paths and return.
        /// </summary>
        /// <param name="startNode">Node at starting point of divergence.</param>
        /// <param name="divergingNodes">List of diverging nodes.</param>
        /// <param name="isForwardExtension">Bool indicating direction of divergence.</param>
        /// <param name="redundantPaths">List of redundant paths.</param>
        private void TraceDivergingExtensionPaths(
            DeBruijnNode startNode,
            Dictionary <DeBruijnNode, bool> divergingNodes,
            bool isForwardExtension,
            List <DeBruijnPathList> redundantPaths)
        {
            List <PathWithOrientation> divergingPaths = new List <PathWithOrientation>(
                divergingNodes.Select(n =>
                                      new PathWithOrientation(startNode, n.Key, n.Value)));
            int divergingPathLengh = 2;

            // Extend paths till length threshold is exceeded.
            // In case paths coverge within threshold, we break out of while.
            while (divergingPathLengh <= this.pathLengthThreshold)
            {
                // Extension is possible only if end point of all paths has exactly one extension
                // In case extensions count is 0, no extensions possible for some path (or)
                // if extensions is more than 1, they are diverging further. Not considered a redundant path
                if (divergingPaths.Any(p => ((isForwardExtension ^ p.IsSameOrientation) ?
                                             p.Nodes.Last().LeftExtensionNodesCount : p.Nodes.Last().RightExtensionNodesCount) != 1))
                {
                    return;
                }

                // Extend each path in cluster. While performing path extension
                // also keep track of whether they have converged
                bool hasConverged = true;
                foreach (PathWithOrientation path in divergingPaths)
                {
                    DeBruijnNode endNode = path.Nodes.Last();
                    Dictionary <DeBruijnNode, bool> extensions
                        = (isForwardExtension ^ path.IsSameOrientation) ? endNode.GetLeftExtensionNodesWithOrientation() : endNode.GetRightExtensionNodesWithOrientation();

                    KeyValuePair <DeBruijnNode, bool> nextNode = extensions.First();
                    if (path.Nodes.Contains(nextNode.Key))
                    {
                        // Loop in path
                        return;
                    }
                    else
                    {
                        // Update path orientation
                        path.IsSameOrientation = !(path.IsSameOrientation ^ nextNode.Value);
                        path.Nodes.Add(nextNode.Key);

                        // Check if paths so far are converged
                        if (hasConverged && nextNode.Key != divergingPaths.First().Nodes.Last())
                        {
                            // Last node added is different. Paths do not converge
                            hasConverged = false;
                        }
                    }
                }

                divergingPathLengh++;

                // Paths have been extended. Check for convergence
                if (hasConverged)
                {
                    // Note: all paths have the same end node.
                    lock (redundantPaths)
                    {
                        // Redundant paths found
                        redundantPaths.Add(new DeBruijnPathList(divergingPaths.Select(p => new DeBruijnPath(p.Nodes))));
                    }

                    return;
                }
            }
        }