private static double[,] GetNearestNeighborMatrix <T>(List <Group> groups) where T : VectorSimilarity
        {
            double[,] nearestNeighborGroupMatrix = new double[groups.Count, groups.Count];
            foreach (Group groupA in groups)
            {
                foreach (Article articleA in groupA.Articles)
                {
                    Article nearestNeighbor      = null;
                    Group   nearestNeighborGroup = null;
                    double  maxSimilarity        = double.MinValue;
                    foreach (Group groupB in groups.Where(g => g.Id != groupA.Id))
                    {
                        foreach (Article articleB in groupB.Articles)
                        {
                            VectorSimilarity vs         = Activator.CreateInstance <T>();
                            double           similarity = vs.GetSimilarity(articleA, articleB);
                            if (similarity > maxSimilarity)
                            {
                                maxSimilarity        = similarity;
                                nearestNeighbor      = articleB;
                                nearestNeighborGroup = groupB;
                            }
                        }
                    }

                    articleA.NearestNeighbor = nearestNeighbor;
                    nearestNeighborGroupMatrix[groupA.Id - 1, nearestNeighborGroup.Id - 1] += 1;
                }
            }

            return(nearestNeighborGroupMatrix);
        }
        private static List <double> CompareArticles <T>(int articleId, List <Group> groups) where T : VectorSimilarity
        {
            List <Article> articles     = new List <Article>(groups.SelectMany(g => g.Articles));
            Article        pivot        = articles.Where(a => a.Id == articleId).Single();
            List <double>  similarities = new List <double>(articles.Count);

            foreach (Article article in articles)
            {
                VectorSimilarity vs = Activator.CreateInstance <T>();
                similarities.Add(vs.GetSimilarity(article, pivot));
            }

            return(similarities);
        }
        private static double CompareGroups(Group a, Group b, Type similarityMethodType)
        {
            int    combinations = 0;
            double accumulator  = 0;

            foreach (Article articleInA in a.Articles)
            {
                foreach (Article articleInB in b.Articles)
                {
                    VectorSimilarity similarityMethod = (VectorSimilarity)Activator.CreateInstance(similarityMethodType);
                    accumulator += similarityMethod.GetSimilarity(articleInA, articleInB);
                    combinations++;
                }
            }

            return(accumulator / combinations);
        }