public Stereotypes newRandomCentroids(Users users, Items items, int cStereotypes)
        {
            Stereotypes stereotypes = new Stereotypes();

            //create random initial stereotype
            List <User> centroids   = new List <User>();
            var         subsetUsers = users.Where(x => x.GetRatedItems().Count > minimumRatingThreshold).ToList();

            centroids.Add(randomGenerator.getRandomUser(subsetUsers));

            double sumSquaredDistanceFromStereotypes;

            //create cStereotypes
            for (int i = 1; i < cStereotypes; i++)
            {
                double farestDistanceFromStereotypes = 0.0;
                User   farestUser = null;

                //find farest user from stereotypes
                foreach (User user in subsetUsers)
                {
                    if (centroids.Contains(user))
                    {
                        continue;
                    }

                    // calculate similarites and update farest centroid accordingly
                    sumSquaredDistanceFromStereotypes = 0.0;
                    List <KeyValuePair <User, double> > disSimilarities = similarityEngine.calculateSimilarity(similarityMethod, user, centroids, true);

                    foreach (KeyValuePair <User, double> disSimilarity in disSimilarities)
                    {
                        sumSquaredDistanceFromStereotypes += Math.Pow(Math.Abs(disSimilarity.Value), 2);
                    }

                    if (sumSquaredDistanceFromStereotypes > farestDistanceFromStereotypes)
                    {
                        farestDistanceFromStereotypes = sumSquaredDistanceFromStereotypes;
                        farestUser = user;
                    }
                }
                if (farestUser == null)
                {
                    throw new ArgumentNullException();
                }

                centroids.Add(farestUser);
            }

            foreach (User user in centroids)
            {
                stereotypes.addStereotype(new Stereotype(user));
            }
            return(stereotypes);
        }
        public void Train()
        {
            Console.WriteLine("***************** Train Stereotypes  Model *********************");
            stereotypes = newRandomCentroids(users, items, cStereotypes);

            Users usersCopy   = new Users(users);
            bool  isConverged = false;
            int   iteration   = 1;

            while (!isConverged && iteration <= MAX_ITERATION)
            {
                Console.WriteLine("Iteration: {0}", iteration);
                List <User> prevCentroids = stereotypes.getStereotypesCentroids();
                stereotypes.initStereotypesUsers();
                List <User> usersWithNoSimilarity = new List <User>();;
                foreach (User user in usersCopy)
                {
                    //Calculate a users similarity to the stereotypes
                    List <KeyValuePair <User, double> > similarities = similarityEngine.calculateSimilarity(similarityMethod, user, prevCentroids, false, true); //TODO - check the similarity threshold for stereotype algorithm

                    //Determine users that don't have a correlation with non of the stereotypes
                    if (similarities.Count == 0)
                    {
                        usersWithNoSimilarity.Add(user);
                        continue;
                    }

                    //Allocate a user to it's most similar stereotype
                    User mostSimilarCentroid = similarities.Last().Key;
                    stereotypes.addUserToStereotype(mostSimilarCentroid.GetId(), user);
                }
                usersCopy.removeUsers(usersWithNoSimilarity);

                //Determine convergence
                stereotypes.reCalculateCentroids();
                List <User> currCentroids = stereotypes.getStereotypesCentroids();
                var         prevAndCurrCentroidsSimilarity = currCentroids.Zip(prevCentroids, (x, y) => Tuple.Create(x, y)).Select(x => Tuple.Create(x.Item1, x.Item2, similarityEngine.calculateSimilarity(similarityMethod, x.Item1, x.Item2))).ToList();
                if (prevAndCurrCentroidsSimilarity.All(x => x.Item3 > CENTROIDS_SIMILARITY_THRESHOLD))
                {
                    isConverged = true;
                }
                else
                {
                    iteration++;
                }
            }
        }