/// <summary>
        /// Expands the specified knowledge structure with new states by applying Rule 2.
        /// </summary>
        ///
        /// <param name="ks">Knowledge structure to be expanded with new states.</param>
        ///
        /// <returns>Expanded knowledge structure</returns>
        public void createExpandedKStructure(KStructure ks)
        {
            // Implements Rule 2:  Given a set GR of problems with a rank R and a set GR-1 of problems with rank R-1,
            // a union of any subset of GR with any knowledge state KR-1 containing at least one problem from GR-1 is a state.

            // [SC] make sure the knowledge structure object is not null
            if (ks == null)
            {
                Log(Severity.Error, "createExpandedKStructure: KStructure object is null. Returning from method.");
                return;
            }

            // [SC] make sure the rank order of categories is available
            if (!ks.hasRankOrder())
            {
                Log(Severity.Error, "createExpandedKStructure: KStructure object contains no rank order. Returning from method.");
                return;
            }

            // [SC] make sure the knowledge structure has ranks
            if (!ks.hasRanks())
            {
                Log(Severity.Error, "createExpandedKStructure: KStructure object contains no ranks with states. Returning from method.");
                return;
            }

            Rank prevRank = null;

            foreach (Rank rank in ks.rankOrder.getRanks())
            {
                if (prevRank != null)
                {
                    // [SC] getting all unique subsets of categories in this rank
                    List <List <PCategory> > subsets = rank.getSubsets();

                    // [SC] retrieve all KS ranks with minimum required state size
                    List <KSRank> ksRanks = ks.getRanks().FindAll(rankOne => rankOne.RankIndex >= prevRank.RankIndex);

                    if (ksRanks == null || ksRanks.Count == 0)
                    {
                        continue;
                    }

                    // [SC] this list contains all relevant states that contain any category from GR-1
                    List <KState> states = new List <KState>();
                    foreach (KSRank ksRank in ksRanks)
                    {
                        // [SC] From given KS rank, retrieve all states that contain at least one problem from GR-1 and add them to the common list
                        states.AddRange(ksRank.getStates().FindAll(stateOne => stateOne.getCategories().Intersect(prevRank.getCategories()).Any()));
                    }

                    if (states.Count == 0)
                    {
                        continue;
                    }

                    // [SC] iterate through subsets of GR
                    foreach (List <PCategory> subset in subsets)
                    {
                        foreach (KState state in states)
                        {
                            // [SC] if state already contains the entire subset then skip it
                            if (state.getCategories().Intersect(subset).Count() == subset.Count)
                            {
                                continue;
                            }

                            // [SC] creating a new state
                            KState newState = new KState(KSGenerator.EXPANDED_STATE);
                            foreach (PCategory category in state.getCategories())
                            {
                                newState.addCategory(category);
                            }
                            foreach (PCategory category in subset)
                            {
                                newState.addCategory(category);
                            }

                            // [SC] add the new state to the respective rank
                            KSRank newStateRank = ks.getRanks().Find(rankOne => rankOne.RankIndex == newState.getCategoryCount());
                            if (newStateRank.addState(newState))
                            {
                                newState.Id = KSGenerator.getStateID(newStateRank.RankIndex, newStateRank.getStateCount());

                                // [SC] link the new state with previous states of lower rank
                                KSRank prevStateRank = ks.getRanks().Find(rankOne => rankOne.RankIndex == newState.getCategoryCount() - 1);
                                if (prevStateRank != null)
                                {
                                    foreach (KState prevState in prevStateRank.getStates())
                                    {
                                        if (prevState.isSubsetOf(newState))
                                        {
                                            prevState.addNextState(newState);
                                            newState.addPrevState(prevState);
                                        }
                                    }
                                }

                                // [SC] link the new state with next states of higher rank
                                KSRank nextStateRank = ks.getRanks().Find(rankOne => rankOne.RankIndex == newState.getCategoryCount() + 1);
                                if (nextStateRank != null)
                                {
                                    foreach (KState nextState in nextStateRank.getStates())
                                    {
                                        if (newState.isSubsetOf(nextState))
                                        {
                                            nextState.addPrevState(newState);
                                            newState.addNextState(nextState);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                prevRank = rank;
            }
        }