/// <summary>
        ///   The most conservative method due to the fact that it minimizes the worst of correlations
        ///   min ( max (MI(s,t)))
        ///   where s is a permutation and t is a member of the group
        ///   Assign  MI to a group to be the maximum of the MIs between s and any member of
        ///   this group. Select the minimum of these across groups and unselected indeces
        /// </summary>
        protected void FillGroupsConservative()
        {
            for (int i = 0; i < minimalMutualInfoGroups.Length; i++)
            {
                if (minimalMutualInfoGroups[i].Count != 1)
                {
                    throw new ConstraintException("The groups shouldn't be full or uninitialized");
                }
            }

            while (true)
            {
                double minMi           = double.MaxValue;
                int    groupIndexToAdd = -1;
                int    uniqueIndex     = -1;
                bool   finished        = true;
                for (int i = 0; i < indexList.Count; i++)
                {
                    for (int j = 0; j < minimalMutualInfoGroups.Length; j++)
                    {
                        double groupMax = 0.0;
                        if (minimalMutualInfoGroups[j].Count == minimalMutualInfoGroups[j].GroupSize)
                        {
                            continue;
                        }

                        finished = false;
                        for (int k = 0; k < minimalMutualInfoGroups[j].Count; k++)
                        {
                            // Find mi between selected index and current member of the group
                            MinimalMutualInfoPair mi = mmiPairs.Find(
                                pair => (pair.IndexFirst == indexList[i] && pair.IndexSecond == minimalMutualInfoGroups[j][k]) ||
                                (pair.IndexFirst == minimalMutualInfoGroups[j][k] && pair.IndexSecond == indexList[i]));
                            if (mi.MutualInformation > groupMax)
                            {
                                groupMax = mi.MutualInformation;
                            }
                        }

                        if (minMi > groupMax)
                        {
                            minMi           = groupMax;
                            groupIndexToAdd = j;
                            uniqueIndex     = indexList[i];
                        }
                    }
                }

                if (finished)
                {
                    break;
                }

                indexList.Remove(uniqueIndex);
                minimalMutualInfoGroups[groupIndexToAdd].AddToGroup(uniqueIndex);
            }
        }
        /// <summary>
        ///  The most agressive of the methods min ( min (MI(s,t)))
        ///  where s is a permutation and t is a member of the group
        /// </summary>
        protected void FillGroupsAgressive()
        {
            for (int i = 0; i < minimalMutualInfoGroups.Length; i++)
            {
                if (minimalMutualInfoGroups[i].Count != 1)
                {
                    throw new ConstraintException("The groups shouldn't be full or uninitialized");
                }
            }

            while (true)
            {
                MinimalMutualInfoPair minMi = new MinimalMutualInfoPair(-1, -1, double.MaxValue);
                int groupIndexToAdd         = -1;
                int uniqueIndex             = -1;
                for (int i = 0; i < indexList.Count; i++)
                {
                    for (int j = 0; j < minimalMutualInfoGroups.Length; j++)
                    {
                        if (minimalMutualInfoGroups[j].Count == minimalMutualInfoGroups[j].GroupSize)
                        {
                            continue;
                        }

                        for (int k = 0; k < minimalMutualInfoGroups[j].Count; k++)
                        {
                            // Find mi between selected index and current member of the group
                            MinimalMutualInfoPair mi = mmiPairs.Find(
                                pair => (pair.IndexFirst == indexList[i] && pair.IndexSecond == minimalMutualInfoGroups[j][k]) ||
                                (pair.IndexFirst == minimalMutualInfoGroups[j][k] && pair.IndexSecond == indexList[i]));
                            if (minMi.MutualInformation > mi.MutualInformation)
                            {
                                minMi           = mi;
                                groupIndexToAdd = j;
                                uniqueIndex     = minimalMutualInfoGroups[j].Contains(minMi.IndexFirst) ? minMi.IndexSecond : minMi.IndexFirst;
                            }
                        }
                    }
                }

                if (minMi.IndexFirst == -1)
                {
                    break;
                }

                indexList.Remove(uniqueIndex);
                minimalMutualInfoGroups[groupIndexToAdd].AddToGroup(uniqueIndex);
            }
        }
        /// <summary>
        ///  The most agressive of the methods min ( min (MI(s,t)))
        ///  where s is a permutation and t is a member of the group
        /// </summary>
        protected void FillGroupsAgressive()
        {
            for (int i = 0; i < minimalMutualInfoGroups.Length; i++)
            {
                if (minimalMutualInfoGroups[i].Count != 1)
                {
                    throw new ConstraintException("The groups shouldn't be full or uninitialized");
                }
            }

            while (true)
            {
                MinimalMutualInfoPair minMi = new MinimalMutualInfoPair(-1, -1, double.MaxValue);
                int groupIndexToAdd = -1;
                int uniqueIndex = -1;
                for (int i = 0; i < indexList.Count; i++)
                {
                    for (int j = 0; j < minimalMutualInfoGroups.Length; j++)
                    {
                        if (minimalMutualInfoGroups[j].Count == minimalMutualInfoGroups[j].GroupSize)
                        {
                            continue;
                        }

                        for (int k = 0; k < minimalMutualInfoGroups[j].Count; k++)
                        {
                            // Find mi between selected index and current member of the group
                            MinimalMutualInfoPair mi = mmiPairs.Find(
                                pair => (pair.IndexFirst == indexList[i] && pair.IndexSecond == minimalMutualInfoGroups[j][k]) ||
                                        (pair.IndexFirst == minimalMutualInfoGroups[j][k] && pair.IndexSecond == indexList[i]));
                            if (minMi.MutualInformation > mi.MutualInformation)
                            {
                                minMi = mi;
                                groupIndexToAdd = j;
                                uniqueIndex = minimalMutualInfoGroups[j].Contains(minMi.IndexFirst) ? minMi.IndexSecond : minMi.IndexFirst;
                            }
                        }
                    }
                }

                if (minMi.IndexFirst == -1)
                {
                    break;
                }

                indexList.Remove(uniqueIndex);
                minimalMutualInfoGroups[groupIndexToAdd].AddToGroup(uniqueIndex);
            }
        }