/// <summary>
        /// Finds related items for every item in a given instance source.
        /// The subset of items which will be returned as related for a particular item is restricted:
        /// it is guaranteed that all the related items have been rated by at least <paramref name="minCommonRatingCount"/> users in common with the query item
        /// in the dataset.
        /// </summary>
        /// <typeparam name="TFeatureSource">The type of a feature source used by the recommendation engine.</typeparam>
        /// <param name="recommender">The recommendation engine.</param>
        /// <param name="instanceSource">The instance source.</param>
        /// <param name="maxRelatedItemCount">Maximum number of related items to return.</param>
        /// <param name="minCommonRatingCount">Minimum number of users that the query item and the related item should have been rated by in common.</param>
        /// <param name="minRelatedItemPoolSize">
        /// If an item has less than <paramref name="minRelatedItemPoolSize"/> possible related items,
        /// it will be skipped.
        /// </param>
        /// <param name="featureSource">The source of features.</param>
        /// <returns>The list of related items for every item in <paramref name="instanceSource"/>.</returns>
        public IDictionary <TItem, IEnumerable <TItem> > FindRelatedItemsRatedBySameUsers <TFeatureSource>(
            IRecommender <TInstanceSource, TUser, TItem, TPredictedRating, TPredictedRatingDist, TFeatureSource> recommender,
            TInstanceSource instanceSource,
            int maxRelatedItemCount,
            int minCommonRatingCount,
            int minRelatedItemPoolSize,
            TFeatureSource featureSource = default(TFeatureSource))
        {
            if (recommender == null)
            {
                throw new ArgumentNullException("recommender");
            }

            if (maxRelatedItemCount <= 0)
            {
                throw new ArgumentOutOfRangeException("maxRelatedItemCount", "The maximum number of related items should be positive.");
            }

            if (minCommonRatingCount <= 0)
            {
                throw new ArgumentOutOfRangeException("minCommonRatingCount", "The minimum number of common ratings should be positive.");
            }

            if (minRelatedItemPoolSize <= 0)
            {
                throw new ArgumentOutOfRangeException("minRelatedItemPoolSize", "The minimum size of the related items pool should be positive.");
            }

            return(FindRelatedEntitiesWhichRatedTheSame(
                       this.mapping.GetItems(instanceSource),
                       item => this.mapping.GetItemsRatedBySameUsers(instanceSource, item),
                       (item, itemSubset) =>
            {
                recommender.ItemSubset = itemSubset;
                return recommender.GetRelatedItems(item, maxRelatedItemCount, featureSource);
            },
                       minCommonRatingCount,
                       minRelatedItemPoolSize));
        }