Esempio n. 1
0
        public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending)
        {
            comparer = comparer ?? Comparer <TNewKey> .Default;
            if (descending)
            {
                comparer = comparer.Reverse();
            }
            var compoundComparer = new CustomComparer <(TKey, TNewKey)>(Compare);

            return(new OrderedEnumerable <TElement, (TKey, TNewKey)>(_source, CompoundKeySelector, compoundComparer));

            (TKey, TNewKey) CompoundKeySelector(TElement item)
            {
                return(_keySelector(item), keySelector(item));
            }

            int Compare((TKey, TNewKey) x, (TKey, TNewKey) y)
            {
                var check = _comparer.Compare(x.Item1, y.Item1);

                if (check == 0)
                {
                    return(comparer.Compare(x.Item2, y.Item2));
                }
                return(check);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Sorts the elements of a sequence in descending order according to a key.
        /// Unlike standard Linq NOT a stable sort.
        /// </summary>
        /// <param name="source">A sequence of values to order.</param>
        /// <param name="keySelector">A function to extract a key from an element.</param>
        /// <param name="comparer">A Comparer to compare keys.</param>
        /// <returns>A sequence whose elements are ordered according to a key</returns>
        public static TSource[] OrderByDescendingF <TSource, TKey>(this TSource[] source, Func <TSource, TKey> keySelector, IComparer <TKey> comparer = null)
        {
            if (source == null)
            {
                throw Error.ArgumentNull(nameof(source));
            }

            if (keySelector == null)
            {
                throw Error.ArgumentNull("keySelector");
            }

            if (comparer == null)
            {
                comparer = Comparer <TKey> .Default;
            }

            TKey[] keys = new TKey[source.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                keys[i] = keySelector(source[i]);
            }
            TSource[] result = (TSource[])source.Clone();
            Array.Sort(keys, result, comparer.Reverse());
            return(result);
        }
Esempio n. 3
0
        public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending)
        {
            if (keySelector == null)
            {
                throw new ArgumentNullException(nameof(keySelector));
            }

            comparer = comparer ?? Comparer <TNewKey> .Default;
            if (descending)
            {
                comparer = comparer.Reverse();
            }

            var compoundComparer = new CustomComparer <KeyValuePair <TKey, TNewKey> >(Compare);

            return(new OrderedEnumerable <TElement, KeyValuePair <TKey, TNewKey> >(_source, CompoundKeySelector, compoundComparer));

            KeyValuePair <TKey, TNewKey> CompoundKeySelector(TElement item)
            {
                return(new KeyValuePair <TKey, TNewKey>(_keySelector(item), keySelector(item)));
            }

            int Compare(KeyValuePair <TKey, TNewKey> x, KeyValuePair <TKey, TNewKey> y)
            {
                var check = _comparer.Compare(x.Key, y.Key);

                return(check == 0 ? comparer.Compare(x.Value, y.Value) : check);
            }
        }
Esempio n. 4
0
 public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending)
 {
     comparer = comparer ?? Comparer <TNewKey> .Default;
     if (descending)
     {
         comparer = comparer.Reverse();
     }
     return(new OrderedEnumerable <TElement, TNewKey>(_source, keySelector, comparer));
 }
Esempio n. 5
0
 public OrderedEnumerable(IEnumerable <TElement> source, Func <TElement, TKey> keySelector, IComparer <TKey> comparer, bool descending)
 {
     _comparer = comparer ?? Comparer <TKey> .Default;
     if (descending)
     {
         _comparer = _comparer.Reverse();
     }
     _source      = source ?? throw new ArgumentNullException(nameof(source));
     _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector));
 }
Esempio n. 6
0
        public void SubstitutesCompareDefaultForNull()
        {
            IComparer <int> source   = null;
            var             comparer = source.Reverse();

            Assert.Equal(ComparerBuilder.For <int>().Default().Reverse().ToString(), comparer.ToString());

            var list = Enumerable.Range(0, 5).ToList();

            list.Sort(comparer);
            Assert.Equal(new[] { 4, 3, 2, 1, 0 }, list);
        }
        public int ShouldExtendComparerByReverseMethod(IComparer <object> comparer)
        {
            // given
            var obj1 = new object();
            var obj2 = new object();

            // when
            var reverse = comparer.Reverse();

            // then
            return(reverse.Compare(obj1, obj2));
        }
Esempio n. 8
0
        public void SubstitutesCompareDefaultForNull()
        {
            IComparer <int> source   = null;
            var             comparer = source.Reverse();

            Assert.AreSame(Compare <int> .Default(), (comparer as ReverseComparer <int>).Source);

            var list = Enumerable.Range(0, 5).ToList();

            list.Sort(comparer);
            CollectionAssert.AreEqual(new[] { 4, 3, 2, 1, 0 }, list);
        }
Esempio n. 9
0
 /// <summary>
 /// Returns a comparer that uses another comparer if the source comparer determines the objects are equal.
 /// </summary>
 /// <typeparam name="T">The type of objects being compared.</typeparam>
 /// <param name="source">The source comparer. If this is <c>null</c>, the default comparer is used.</param>
 /// <param name="thenBy">The comparer that is used if <paramref name="source"/> determines the objects are equal. If this is <c>null</c>, the default comparer is used.</param>
 /// <param name="descending">A value indicating whether the sorting is done in descending order. If <c>false</c> (the default), then the sort is in ascending order.</param>
 /// <returns>A comparer that uses another comparer if the source comparer determines the objects are equal.</returns>
 public static IFullComparer <T> ThenBy <T>(this IComparer <T> source, IComparer <T> thenBy, bool descending = false) =>
 new CompoundComparer <T>(source, descending ? thenBy.Reverse() : thenBy);
Esempio n. 10
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();
            }
Esempio n. 11
0
 /// <summary>
 /// Returns a comparer that uses another comparer if the source comparer determines the objects are equal.
 /// </summary>
 /// <typeparam name="T">The type of objects being compared.</typeparam>
 /// <param name="source">The source comparer. If this is <c>null</c>, the default comparer is used.</param>
 /// <param name="thenBy">The comparer that is used if <paramref name="source"/> determines the objects are equal. If this is <c>null</c>, the default comparer is used.</param>
 /// <param name="descending">A value indicating whether the sorting is done in descending order. If <c>false</c> (the default), then the sort is in ascending order.</param>
 /// <returns>A comparer that uses another comparer if the source comparer determines the objects are equal.</returns>
 public static IFullComparer <T> ThenBy <T>(this IComparer <T> source, IComparer <T> thenBy, bool descending = false)
 {
     Contract.Ensures(Contract.Result <IFullComparer <T> >() != null);
     return(new CompoundComparer <T>(source, descending ? thenBy.Reverse() : thenBy));
 }
Esempio n. 12
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);
            }
Esempio n. 13
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);
            }
Esempio n. 14
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);
            }
 /// <summary>
 /// Creates a descending key comparer.
 /// </summary>
 /// <typeparam name="TKey">The type of key objects being compared.</typeparam>
 /// <param name="selector">The key selector. May not be <c>null</c>.</param>
 /// <param name="keyComparer">The key comparer. The returned comparer applies this key comparer in reverse. Defaults to <c>null</c>. If this is <c>null</c>, the default comparer is used.</param>
 /// <param name="allowNulls">A value indicating whether <c>null</c> values are passed to <paramref name="selector"/>. If <c>false</c>, then <c>null</c> values are considered less than any non-<c>null</c> values and are not passed to <paramref name="selector"/>.</param>
 /// <returns>A key comparer.</returns>
 public static IFullComparer <T> OrderByDescending <TKey>(Func <T, TKey> selector, IComparer <TKey> keyComparer = null, bool allowNulls = false)
 {
     Contract.Requires(selector != null);
     Contract.Ensures(Contract.Result <IFullComparer <T> >() != null);
     return(OrderBy <TKey>(selector, keyComparer.Reverse(), allowNulls));
 }