public static List <IVertex> Search(IGraph myGraph, IVertex mySource, IVertex myTarget, Func <IVertex, bool> myMatchingFunc = null)
        {
            // queue for bfs
            var leftQueue  = new Queue <IVertex>();
            var rightQueue = new Queue <IVertex>();

            // store visited nodes in a hashset
            var visitedNodesLeft  = new HashSet <IVertex>();
            var visitedNodesRight = new HashSet <IVertex>();

            var doMatching = myMatchingFunc != null;

            IVertex intersectionVertex = null;

            // init the queue with the source vertex
            mySource[PREDECESSOR_ATTRIBUTE_KEY] = null;
            myTarget[SUCCESSOR_ATTRIBUTE_KEY]   = null;

            leftQueue.Enqueue(mySource);
            rightQueue.Enqueue(myTarget);

            visitedNodesLeft.Add(mySource);
            visitedNodesRight.Add(myTarget);

            IVertex currentLeftVertex  = null;
            IVertex currentRightVertex = null;

            List <IVertex> result = null;

            while (leftQueue.Count > 0 && rightQueue.Count > 0)
            {
                currentLeftVertex  = leftQueue.Dequeue();
                currentRightVertex = rightQueue.Dequeue();

                if (currentLeftVertex.Equals(myTarget))
                {
                    result = PathConcatenation.ConcatPath(myTarget, PREDECESSOR_ATTRIBUTE_KEY);
                    break;
                }
                else if (currentRightVertex.Equals(mySource))
                {
                    result = PathConcatenation.ConcatPath(mySource, PREDECESSOR_ATTRIBUTE_KEY, false);
                    break;
                }

                // check all children left
                foreach (var edge in currentLeftVertex.OutgoingEdges)
                {
                    if (!visitedNodesLeft.Contains(edge.Target))
                    {
                        edge.Target[PREDECESSOR_ATTRIBUTE_KEY] = currentLeftVertex;

                        if (doMatching)
                        {
                            if (myMatchingFunc(edge.Target))
                            {
                                leftQueue.Enqueue(edge.Target);
                                edge.Target[MATCHING_ATTRIBUTE_KEY] = true;
                            }
                            else
                            {
                                edge.Target[MATCHING_ATTRIBUTE_KEY] = false;
                            }
                        }
                        else
                        {
                            leftQueue.Enqueue(edge.Target);
                        }

                        visitedNodesLeft.Add(edge.Target);
                    }
                }

                // check all parents right
                foreach (var edge in currentRightVertex.IncomingEdges)
                {
                    if (!visitedNodesRight.Contains(edge.Source))
                    {
                        edge.Source[SUCCESSOR_ATTRIBUTE_KEY] = currentRightVertex;

                        if (doMatching)
                        {
                            if (myMatchingFunc(edge.Source))
                            {
                                rightQueue.Enqueue(edge.Source);
                                edge.Target[MATCHING_ATTRIBUTE_KEY] = true;
                            }
                            else
                            {
                                edge.Target[MATCHING_ATTRIBUTE_KEY] = false;
                            }
                        }
                        else
                        {
                            rightQueue.Enqueue(edge.Source);
                        }

                        visitedNodesRight.Add(edge.Source);
                    }
                }

                #region check intersect between visited nodes

                intersectionVertex = GetIntersectionVertex(visitedNodesLeft, visitedNodesRight, doMatching);

                if (intersectionVertex != null)
                {
                    // got a connection between the searches
                    List <IVertex> pathLeft  = null;
                    List <IVertex> pathRight = null;

                    if (intersectionVertex[PREDECESSOR_ATTRIBUTE_KEY].Equals(currentLeftVertex))
                    {
                        pathLeft  = PathConcatenation.ConcatPath(intersectionVertex, PREDECESSOR_ATTRIBUTE_KEY);
                        pathRight = PathConcatenation.ConcatPath((IVertex)intersectionVertex[SUCCESSOR_ATTRIBUTE_KEY], SUCCESSOR_ATTRIBUTE_KEY, false);
                    }
                    else
                    {
                        pathLeft  = PathConcatenation.ConcatPath((IVertex)intersectionVertex[PREDECESSOR_ATTRIBUTE_KEY], PREDECESSOR_ATTRIBUTE_KEY);
                        pathRight = PathConcatenation.ConcatPath(intersectionVertex, SUCCESSOR_ATTRIBUTE_KEY, false);
                    }

                    pathLeft.AddRange(pathRight);

                    result = pathLeft;
                    break;
                }

                #endregion
            }

            return(result);
        }
        /// <summary>
        /// BFS for st-connectivity
        /// </summary>
        /// <param name="myGraph"></param>
        /// <param name="mySource"></param>
        /// <param name="myTarget"></param>
        /// <param name="myMatchingFunc"></param>
        /// <returns></returns>
        public static List <IVertex> Search(IGraph myGraph, IVertex mySource, IVertex myTarget, bool myInitGraph, Func <IVertex, bool> myMatchingFunc = null)
        {
            #region Init

            if (myInitGraph)
            {
                InitGraph(myGraph);
            }
            mySource[COLOR_ATTRIBUTE_KEY]       = Color.RED;
            mySource[PREDECESSOR_ATTRIBUTE_KEY] = null;
            myTarget[COLOR_ATTRIBUTE_KEY]       = Color.GREEN;
            myTarget[PREDECESSOR_ATTRIBUTE_KEY] = null;

            // bool if matching function has to be called
            var doMatching = myMatchingFunc != null;

            // used to indicate that the target node has been found
            var done = false;

            // use Concurrent Queue for parallel access
            var queue = new Queue <IVertex>();

            IVertex u = null;

            #endregion

            #region BFS

            // enqueue the source vertex
            queue.Enqueue(mySource);

            while (queue.Count > 0 && !done)
            {
                u = queue.Dequeue();

                // process neighbours in parallel
                //Parallel.ForEach<IEdge>(u.OutgoingEdges, outEdge =>
                foreach (var outEdge in u.OutgoingEdges)
                {
                    // neighbour node
                    var v = outEdge.Target;
                    // get the color of that neighbour
                    var color = (Color)v[COLOR_ATTRIBUTE_KEY];

                    if (color == Color.WHITE) // not the target
                    {
                        // set as visited (Color.RED)
                        v[COLOR_ATTRIBUTE_KEY] = Color.RED;
                        // set the predecessor
                        v[PREDECESSOR_ATTRIBUTE_KEY] = u;
                        // and enqueue that node (if matching condition == true)
                        if (doMatching)
                        {
                            // matches condition?
                            if (myMatchingFunc(v))
                            {
                                // matches, enqueue
                                queue.Enqueue(v);
                            }
                            // do nothing
                        }
                        else
                        {
                            // no matching necessary
                            queue.Enqueue(v);
                        }
                    }
                    else if (color == Color.GREEN) // done
                    {
                        // finished
                        done = true;
                        // set the predecessor
                        v[PREDECESSOR_ATTRIBUTE_KEY] = u;
                    }
                }
                u[COLOR_ATTRIBUTE_KEY] = Color.RED;
            }

            #endregion

            if (done)
            {
                return(PathConcatenation.ConcatPath(myTarget, PREDECESSOR_ATTRIBUTE_KEY));
            }

            return(null);
        }
        /// <summary>
        /// BFS for st-connectivity
        /// </summary>
        /// <param name="myGraph"></param>
        /// <param name="mySource"></param>
        /// <param name="myTarget"></param>
        /// <param name="myMatchingFunc"></param>
        /// <returns></returns>
        public static List <IVertex> Search(IGraph myGraph, IVertex mySource, IVertex myTarget, bool myInitGraph, Func <IVertex, bool> myMatchingFunc = null)
        {
            #region Init

            if (myInitGraph)
            {
                InitGraph(myGraph);
            }
            mySource[COLOR_ATTRIBUTE_KEY]       = Color.RED;
            mySource[PREDECESSOR_ATTRIBUTE_KEY] = null;
            myTarget[COLOR_ATTRIBUTE_KEY]       = Color.GREEN;
            myTarget[PREDECESSOR_ATTRIBUTE_KEY] = null;

            var doMatching = myMatchingFunc != null;

            // used to indicate that the target node has been found
            var done = false;

            // use Concurrent Queue for parallel access
            var from    = new List <IVertex>();
            var to      = new List <IVertex>();
            var lockObj = new Object();
            OrderablePartitioner <Tuple <int, int> > partitioner;

            #endregion

            #region BFS

            // enqueue the source vertex
            from.Add(mySource);

            while (from.Count > 0 && !done)
            {
                to          = new List <IVertex>();
                partitioner = Partitioner.Create(0, from.Count);

                // process queue in parallel
                Parallel.ForEach(
                    // the values to be aggregated
                    partitioner,
                    // local initial partial result
                    () => new List <IVertex>(),
                    // loop body
                    (range, loopState, partialResult) =>
                {
                    for (int i = range.Item1; i < range.Item2; i++)
                    {
                        IVertex u = from[i];
                        //Parallel.ForEach<IEdge>(u.OutgoingEdges, outEdge =>
                        foreach (var outEdge in u.OutgoingEdges)
                        {
                            // neighbour node
                            var v = outEdge.Target;
                            // get the color of that neighbour
                            var color = (Color)v[COLOR_ATTRIBUTE_KEY];

                            if (color == Color.WHITE)     // not the target
                            {
                                // set as visited (Color.RED)
                                v[COLOR_ATTRIBUTE_KEY] = Color.RED;
                                // set the predecessor
                                v[PREDECESSOR_ATTRIBUTE_KEY] = u;
                                // and enqueue that node (if matching condition == true)
                                if (doMatching)
                                {
                                    // matches condition?
                                    if (myMatchingFunc(v))
                                    {
                                        // matches, add to local set
                                        partialResult.Add(v);
                                    }
                                    // do nothing
                                }
                                else
                                {
                                    // no matching necessary, add to local set
                                    partialResult.Add(v);
                                }
                            }
                            else if (color == Color.GREEN)     // done
                            {
                                // finished
                                done = true;
                                // set the predecessor
                                v[PREDECESSOR_ATTRIBUTE_KEY] = u;
                            }
                            //});
                        }
                        u[COLOR_ATTRIBUTE_KEY] = Color.RED;
                    }

                    return(partialResult);
                },
                    //the final step of each local context
                    (localPartialSet) =>
                {
                    lock (lockObj)
                    {
                        // sloooooow
                        //to = to.Union<IVertex>(localPartialSet).ToList();
                        to.AddRange(localPartialSet);
                    }
                });

                from = to;
            }

            #endregion


            if (done)
            {
                return(PathConcatenation.ConcatPath(myTarget, PREDECESSOR_ATTRIBUTE_KEY));
            }

            return(null);
        }