/// <inheritdoc/>
            internal override List <int> SelectBestForConnecting(List <int> candidatesIds, TravelingCosts <int, TDistance> travelingCosts, int layer)
            {
                /*
                 * q ← this
                 * return M nearest elements from C to q
                 */

                // !NO COPY! in-place selection
                var bestN          = GetM(layer);
                var candidatesHeap = new BinaryHeap <int>(candidatesIds, travelingCosts);

                while (candidatesHeap.Buffer.Count > bestN)
                {
                    candidatesHeap.Pop();
                }

                return(candidatesHeap.Buffer);
            }
Example #2
0
            /// <inheritdoc />
            public override IList <Node> SelectBestForConnecting(IList <Node> candidates)
            {
                /*
                 * q ← this
                 * return M nearest elements from C to q
                 */

                IComparer <Node> fartherIsLess = this.TravelingCosts.Reverse();
                var candidatesHeap             = new BinaryHeap <Node>(candidates, fartherIsLess);

                var result = new List <Node>(GetM(this.Parameters.M, this.MaxLevel) + 1);

                while (candidatesHeap.Buffer.Any() && result.Count < GetM(this.Parameters.M, this.MaxLevel))
                {
                    result.Add(candidatesHeap.Pop());
                }

                return(result);
            }
Example #3
0
            /// <summary>
            /// The implementaiton of SEARCH-LAYER(q, ep, ef, lc) algorithm.
            /// Article: Section 4. Algorithm 2.
            /// </summary>
            /// <param name="entryPointId">The identifier of the entry point for the search.</param>
            /// <param name="targetCosts">The traveling costs for the search target.</param>
            /// <param name="resultList">The list of identifiers of the nearest neighbours at the level.</param>
            /// <param name="layer">The layer to perform search at.</param>
            /// <param name="k">The number of the nearest neighbours to get from the layer.</param>
            internal void RunKnnAtLayer(int entryPointId, TravelingCosts <int, TDistance> targetCosts, IList <int> resultList, int layer, int k)
            {
                /*
                 * v ← ep // set of visited elements
                 * C ← ep // set of candidates
                 * W ← ep // dynamic list of found nearest neighbors
                 * while │C│ > 0
                 *   c ← extract nearest element from C to q
                 *   f ← get furthest element from W to q
                 *   if distance(c, q) > distance(f, q)
                 *     break // all elements in W are evaluated
                 *   for each e ∈ neighbourhood(c) at layer lc // update C and W
                 *     if e ∉ v
                 *       v ← v ⋃ e
                 *       f ← get furthest element from W to q
                 *       if distance(e, q) < distance(f, q) or │W│ < ef
                 *         C ← C ⋃ e
                 *         W ← W ⋃ e
                 *         if │W│ > ef
                 *           remove furthest element from W to q
                 * return W
                 */

                // prepare tools
                IComparer <int> fartherIsOnTop = targetCosts;
                IComparer <int> closerIsOnTop  = fartherIsOnTop.Reverse();

                // prepare collections
                // TODO: Optimize by providing buffers
                var resultHeap    = new BinaryHeap <int>(resultList, fartherIsOnTop);
                var expansionHeap = new BinaryHeap <int>(this.expansionBuffer, closerIsOnTop);

                resultHeap.Push(entryPointId);
                expansionHeap.Push(entryPointId);
                this.visitedSet.Add(entryPointId);

                // run bfs
                while (expansionHeap.Buffer.Count > 0)
                {
                    // get next candidate to check and expand
                    var toExpandId       = expansionHeap.Pop();
                    var farthestResultId = resultHeap.Buffer[0];
                    if (DistanceUtils.Gt(targetCosts.From(toExpandId), targetCosts.From(farthestResultId)))
                    {
                        // the closest candidate is farther than farthest result
                        break;
                    }

                    // expand candidate
                    var neighboursIds = this.core.Nodes[toExpandId][layer];
                    for (int i = 0; i < neighboursIds.Count; ++i)
                    {
                        int neighbourId = neighboursIds[i];
                        if (!this.visitedSet.Contains(neighbourId))
                        {
                            // enque perspective neighbours to expansion list
                            farthestResultId = resultHeap.Buffer[0];
                            if (resultHeap.Buffer.Count < k ||
                                DistanceUtils.Lt(targetCosts.From(neighbourId), targetCosts.From(farthestResultId)))
                            {
                                expansionHeap.Push(neighbourId);
                                resultHeap.Push(neighbourId);
                                if (resultHeap.Buffer.Count > k)
                                {
                                    resultHeap.Pop();
                                }
                            }

                            // update visited list
                            this.visitedSet.Add(neighbourId);
                        }
                    }
                }

                this.expansionBuffer.Clear();
                this.visitedSet.Clear();
            }
Example #4
0
            /// <summary>
            /// The implementaiton of SEARCH-LAYER(q, ep, ef, lc) algorithm.
            /// Article: Section 4. Algorithm 2.
            /// </summary>
            /// <param name="entryPoint">The entry point for the search.</param>
            /// <param name="destination">The search target.</param>
            /// <param name="k">The number of the nearest neighbours to get from the layer.</param>
            /// <param name="level">Level of the layer.</param>
            /// <returns>The list of the nearest neighbours at the level.</returns>
            private static IList <Node> KNearestAtLevel(Node entryPoint, Node destination, int k, int level)
            {
                /*
                 * v ← ep // set of visited elements
                 * C ← ep // set of candidates
                 * W ← ep // dynamic list of found nearest neighbors
                 * while │C│ > 0
                 *   c ← extract nearest element from C to q
                 *   f ← get furthest element from W to q
                 *   if distance(c, q) > distance(f, q)
                 *     break // all elements in W are evaluated
                 *   for each e ∈ neighbourhood(c) at layer lc // update C and W
                 *     if e ∉ v
                 *       v ← v ⋃ e
                 *       f ← get furthest element from W to q
                 *       if distance(e, q) < distance(f, q) or │W│ < ef
                 *         C ← C ⋃ e
                 *         W ← W ⋃ e
                 *         if │W│ > ef
                 *           remove furthest element from W to q
                 * return W
                 */

                // prepare tools
                IComparer <Node> closerIsLess  = destination.TravelingCosts;
                IComparer <Node> fartherIsLess = closerIsLess.Reverse();

                // prepare heaps
                var resultHeap = new BinaryHeap <Node>(new List <Node>(k + 1)
                {
                    entryPoint
                }, closerIsLess);
                var expansionHeap = new BinaryHeap <Node>(new List <Node>()
                {
                    entryPoint
                }, fartherIsLess);

                // run bfs
                var visited = new HashSet <int>()
                {
                    entryPoint.Id
                };

                while (expansionHeap.Buffer.Any())
                {
                    // get next candidate to check and expand
                    var toExpand       = expansionHeap.Pop();
                    var farthestResult = resultHeap.Buffer.First();
                    if (DGt(destination.TravelingCosts.From(toExpand), destination.TravelingCosts.From(farthestResult)))
                    {
                        // the closest candidate is farther than farthest result
                        break;
                    }

                    // expand candidate
                    foreach (var neighbour in toExpand.GetConnections(level))
                    {
                        if (!visited.Contains(neighbour.Id))
                        {
                            // enque perspective neighbours to expansion list
                            farthestResult = resultHeap.Buffer.First();
                            if (resultHeap.Buffer.Count < k ||
                                DLt(destination.TravelingCosts.From(neighbour), destination.TravelingCosts.From(farthestResult)))
                            {
                                expansionHeap.Push(neighbour);
                                resultHeap.Push(neighbour);
                                if (resultHeap.Buffer.Count > k)
                                {
                                    resultHeap.Pop();
                                }
                            }

                            // update visited list
                            visited.Add(neighbour.Id);
                        }
                    }
                }

                return(resultHeap.Buffer);
            }
Example #5
0
            /// <inheritdoc />
            public override IList <Node> SelectBestForConnecting(IList <Node> candidates)
            {
                /*
                 * q ← this
                 * R ← ∅    // result
                 * W ← C    // working queue for the candidates
                 * if expandCandidates  // expand candidates
                 *   for each e ∈ C
                 *     for each eadj ∈ neighbourhood(e) at layer lc
                 *       if eadj ∉ W
                 *         W ← W ⋃ eadj
                 *
                 * Wd ← ∅ // queue for the discarded candidates
                 * while │W│ gt 0 and │R│ lt M
                 *   e ← extract nearest element from W to q
                 *   if e is closer to q compared to any element from R
                 *     R ← R ⋃ e
                 *   else
                 *     Wd ← Wd ⋃ e
                 *
                 * if keepPrunedConnections // add some of the discarded connections from Wd
                 *   while │Wd│ gt 0 and │R│ lt M
                 *   R ← R ⋃ extract nearest element from Wd to q
                 *
                 * return R
                 */

                IComparer <Node> closerIsLess  = this.TravelingCosts;
                IComparer <Node> fartherIsLess = closerIsLess.Reverse();

                var resultHeap     = new BinaryHeap <Node>(new List <Node>(GetM(this.Parameters.M, this.MaxLevel) + 1), closerIsLess);
                var candidatesHeap = new BinaryHeap <Node>(candidates, fartherIsLess);

                // expand candidates option is enabled
                if (this.Parameters.ExpandBestSelection)
                {
                    var candidatesIds = new HashSet <int>(candidates.Select(c => c.Id));
                    foreach (var neighbour in this.GetConnections(this.MaxLevel))
                    {
                        if (!candidatesIds.Contains(neighbour.Id))
                        {
                            candidatesHeap.Push(neighbour);
                            candidatesIds.Add(neighbour.Id);
                        }
                    }
                }

                // main stage of moving candidates to result
                var discardedHeap = new BinaryHeap <Node>(new List <Node>(candidatesHeap.Buffer.Count), fartherIsLess);

                while (candidatesHeap.Buffer.Any() && resultHeap.Buffer.Count < GetM(this.Parameters.M, this.MaxLevel))
                {
                    var candidate    = candidatesHeap.Pop();
                    var farestResult = resultHeap.Buffer.FirstOrDefault();

                    if (farestResult == null ||
                        DLt(this.TravelingCosts.From(candidate), this.TravelingCosts.From(farestResult)))
                    {
                        resultHeap.Push(candidate);
                    }
                    else if (this.Parameters.KeepPrunedConnections)
                    {
                        discardedHeap.Push(candidate);
                    }
                }

                // keep pruned option is enabled
                if (this.Parameters.KeepPrunedConnections)
                {
                    while (discardedHeap.Buffer.Any() && resultHeap.Buffer.Count < GetM(this.Parameters.M, this.MaxLevel))
                    {
                        resultHeap.Push(discardedHeap.Pop());
                    }
                }

                return(resultHeap.Buffer);
            }
Example #6
0
            /// <inheritdoc/>
            internal override List <int> SelectBestForConnecting(List <int> candidatesIds, TravelingCosts <int, TDistance> travelingCosts, int layer)
            {
                /*
                 * q ← this
                 * R ← ∅    // result
                 * W ← C    // working queue for the candidates
                 * if expandCandidates  // expand candidates
                 *   for each e ∈ C
                 *     for each eadj ∈ neighbourhood(e) at layer lc
                 *       if eadj ∉ W
                 *         W ← W ⋃ eadj
                 *
                 * Wd ← ∅ // queue for the discarded candidates
                 * while │W│ gt 0 and │R│ lt M
                 *   e ← extract nearest element from W to q
                 *   if e is closer to q compared to any element from R
                 *     R ← R ⋃ e
                 *   else
                 *     Wd ← Wd ⋃ e
                 *
                 * if keepPrunedConnections // add some of the discarded connections from Wd
                 *   while │Wd│ gt 0 and │R│ lt M
                 *   R ← R ⋃ extract nearest element from Wd to q
                 *
                 * return R
                 */

                IComparer <int> fartherIsOnTop = travelingCosts;
                IComparer <int> closerIsOnTop  = fartherIsOnTop.Reverse();

                var layerM = GetM(layer);

                var resultHeap     = new BinaryHeap <int>(new List <int>(layerM + 1), fartherIsOnTop);
                var candidatesHeap = new BinaryHeap <int>(candidatesIds, closerIsOnTop);

                // expand candidates option is enabled
                if (GraphCore.Parameters.ExpandBestSelection)
                {
                    var visited = new HashSet <int>(candidatesHeap.Buffer);
                    var toAdd   = new HashSet <int>();
                    foreach (var candidateId in candidatesHeap.Buffer)
                    {
                        var candidateNeighborsIDs = GraphCore.Nodes[candidateId][layer];
                        foreach (var candidateNeighbourId in candidateNeighborsIDs)
                        {
                            if (!visited.Contains(candidateNeighbourId))
                            {
                                toAdd.Add(candidateNeighbourId);
                                visited.Add(candidateNeighbourId);
                            }
                        }
                    }
                    foreach (var id in toAdd)
                    {
                        candidatesHeap.Push(id);
                    }
                }

                // main stage of moving candidates to result
                var discardedHeap = new BinaryHeap <int>(new List <int>(candidatesHeap.Buffer.Count), closerIsOnTop);

                while (candidatesHeap.Buffer.Any() && resultHeap.Buffer.Count < layerM)
                {
                    var candidateId    = candidatesHeap.Pop();
                    var farestResultId = resultHeap.Buffer.FirstOrDefault();

                    if (!resultHeap.Buffer.Any() || DistanceUtils.LowerThan(travelingCosts.From(candidateId), travelingCosts.From(farestResultId)))
                    {
                        resultHeap.Push(candidateId);
                    }
                    else if (GraphCore.Parameters.KeepPrunedConnections)
                    {
                        discardedHeap.Push(candidateId);
                    }
                }

                // keep pruned option is enabled
                if (GraphCore.Parameters.KeepPrunedConnections)
                {
                    while (discardedHeap.Buffer.Any() && resultHeap.Buffer.Count < layerM)
                    {
                        resultHeap.Push(discardedHeap.Pop());
                    }
                }

                return(resultHeap.Buffer);
            }