/// <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; } }
/// <summary> /// creates an XML document object from a given KStructure object /// </summary> /// /// <param name="kStructure">KStructure object with a rank order and knowledge structure</param> /// /// <returns>XmlDocument object</returns> public XDocument createXml(KStructure kStructure) { // [SC] verifying that KStructure object is not null if (kStructure == null) { Log(Severity.Error, "Unable to transform knowledge structure into XML format. kStructure parameter is null. Returning null."); return(null); } // [SC] create xml document object XDocument doc = new XDocument(); // [SC] add xml declaration to the document doc.Declaration = new XDeclaration("1.0", "UTF-8", "yes"); // [SC] add a root element 'TwoA' and declare namespace attributes XElement twoAElem = new XElement(XMLFactory.TWOA_ELEM , new XAttribute(XMLFactory.XMLNS_ATTR, XMLFactory.twoa) , new XAttribute(XMLFactory.XSD_ATTR, XMLFactory.xsd) ); doc.Add(twoAElem); // [SC] create a list of categories and a rank order if (kStructure.hasRankOrder()) { RankOrder rankOrder = kStructure.rankOrder; rankOrder.sortAscending(); // [SC] add 'TwoA/PCategories' list element XElement pcatsElem = new XElement(XMLFactory.PCATS_ELEM); twoAElem.Add(pcatsElem); // [SC] add 'TwoA/RankOrder' element XElement rankOrderElem = new XElement(XMLFactory.RANKORDER_ELEM); twoAElem.Add(rankOrderElem); // [SC] add 'TwoA/RankOrder/Params' list element XElement rankParamsElem = new XElement(XMLFactory.PARAMS_ELEM); rankOrderElem.Add(rankParamsElem); // [SC] add 'TwoA/RankOrder/Params.Threshold' element XElement thresholdElem = new XElement(XMLFactory.THRESHOLD_ELEM); rankParamsElem.Add(thresholdElem); thresholdElem.SetValue("" + rankOrder.Threshold); // [SC] create 'TwoA/RankOrder/Ranks' list element XElement ranksElem = new XElement(XMLFactory.RANKS_ELEM); rankOrderElem.Add(ranksElem); // [SC] iterate through ranks and create correspoinding XML elements for (int rankCounter = 0; rankCounter < rankOrder.getRankCount(); rankCounter++) { Rank rank = rankOrder.getRankAt(rankCounter); // [SC] add 'TwoA/RankOrder/Ranks/Rank' element XElement rankElem = new XElement(XMLFactory.RANK_ELEM); ranksElem.Add(rankElem); // [SC] add 'TwoA/RankOrder/Ranks/Rank@Index' attribute to the 'Rank' element XAttribute indexAttr = new XAttribute(XMLFactory.INDEX_ATTR, "" + rank.RankIndex); rankElem.Add(indexAttr); // [SC] interate through categories in the rank and create corresponding XML element and reference to it for (int catCounter = 0; catCounter < rank.getCategoryCount(); catCounter++) { PCategory pcat = rank.getCategoryAt(catCounter); // [SC] add 'TwoA/PCategories/PCategory' element with 'xsd:id' attribute XElement pcatElem = new XElement(XMLFactory.PCAT_ELEM); pcatsElem.Add(pcatElem); // [SC] add 'TwoA/PCategories/PCategory@xsd:id' attribute XAttribute idAttr = new XAttribute(XMLFactory.ID_ATTR, "" + pcat.Id); pcatElem.Add(idAttr); // [SC] add 'TwoA/PCategories/PCategory/Rating' element XElement ratingElem = new XElement(XMLFactory.RATING_ELEM); pcatElem.Add(ratingElem); ratingElem.SetValue("" + pcat.Rating); // [SC] add 'TwoA/RankOrder/Ranks/Rank/PCategory' element with 'xsd:idref' attribute XElement pcatRefElem = new XElement(XMLFactory.PCAT_ELEM); rankElem.Add(pcatRefElem); // [SC] add 'TwoA/RankOrder/Ranks/Rank/PCategory@xsd:idref' attribute XAttribute idrefAttr = new XAttribute(XMLFactory.IDREF_ATTR, "" + pcat.Id); pcatRefElem.Add(idrefAttr); } } } else { Log(Severity.Warning, "Rank order is missing while transforming KStructure object into XML format."); } // [SC] creates elements for 'KStructure' if (kStructure.hasRanks()) { kStructure.sortAscending(); // [SC] add 'TwoA/KStructure' element XElement kStructureElem = new XElement(XMLFactory.KSTRUCTURE_ELEM); twoAElem.Add(kStructureElem); // [SC] iterate through KSRanks and create corresponding XML elements for (int rankCounter = 0; rankCounter < kStructure.getRankCount(); rankCounter++) { KSRank rank = kStructure.getRankAt(rankCounter); // [SC] add 'TwoA/KStructure/KSRank' element XElement ksRankElem = new XElement(XMLFactory.KSRANK_ELEM); kStructureElem.Add(ksRankElem); // [SC] add 'TwoA/KStructure/KSRank@Index' attribute XAttribute indexAttr = new XAttribute(XMLFactory.INDEX_ATTR, "" + rank.RankIndex); ksRankElem.Add(indexAttr); // [SC] iterate through states and add corresponding XML elements for (int stateCounter = 0; stateCounter < rank.getStateCount(); stateCounter++) { KState state = rank.getStateAt(stateCounter); // [SC] add 'TwoA/KStructure/KSRank/KState' element with 'xsd:id' attribute XElement stateElem = new XElement(XMLFactory.KSTATE_ELEM); ksRankElem.Add(stateElem); // [SC] add 'TwoA/KStructure/KSRank/KState@xsd:id' attribute XAttribute idAttr = new XAttribute(XMLFactory.ID_ATTR, "" + state.Id); stateElem.Add(idAttr); // [SC] add 'TwoA/KStructure/KSRank/KState@Type' attribute XAttribute typeAttr = new XAttribute(XMLFactory.TYPE_ATTR, "" + state.StateType); stateElem.Add(typeAttr); // [SC] add 'TwoA/KStructure/KSRank/KState/PCategories' list element XElement pcatsElem = new XElement(XMLFactory.PCATS_ELEM); stateElem.Add(pcatsElem); // [SC] iterate through categories in the state for (int catCounter = 0; catCounter < state.getCategoryCount(); catCounter++) { PCategory pcat = state.getCategoryAt(catCounter); // [SC] add 'TwoA/KStructure/KSRank/KState/PCategories/PCategory' element with 'xsd:idref' attribute XElement pcatElem = new XElement(XMLFactory.PCAT_ELEM); pcatsElem.Add(pcatElem); // [SC] add 'TwoA/KStructure/KSRank/KState/PCategories/PCategory@xsd:idref' attribute XAttribute idrefAttr = new XAttribute(XMLFactory.IDREF_ATTR, "" + pcat.Id); pcatElem.Add(idrefAttr); } // [SC] add 'TwoA/KStructure/KSRank/KState/PreviousStates' list element XElement prevStatesElem = new XElement(XMLFactory.PREV_STATES_ELEM); stateElem.Add(prevStatesElem); // [SC] iterate through immediate prerequisite states in the gradient for (int prevStateCounter = 0; prevStateCounter < state.getPrevStateCount(); prevStateCounter++) { KState prevState = state.getPrevStateAt(prevStateCounter); // [SC] add 'TwoA/KStructure/KSRank/KState/PreviousStates/KState' element with 'xsd:idref' attribute XElement prevStateElem = new XElement(XMLFactory.KSTATE_ELEM); prevStatesElem.Add(prevStateElem); // [SC] add 'TwoA/KStructure/KSRank/KState/PreviousStates/KState@xsd:idref' attribute XAttribute idrefAttr = new XAttribute(XMLFactory.IDREF_ATTR, "" + prevState.Id); prevStateElem.Add(idrefAttr); } // [SC] add 'TwoA/KStructure/KSRank/KState/NextStates' list element XElement nextStatesElem = new XElement(XMLFactory.NEXT_STATES_ELEM); stateElem.Add(nextStatesElem); // [SC] iterate through immediate next states in the gradient for (int nextStateCounter = 0; nextStateCounter < state.getNextStateCount(); nextStateCounter++) { KState nextState = state.getNextStateAt(nextStateCounter); // [SC] add 'TwoA/KStructure/KSRank/KState/NextStates/KState' element with 'xsd:idref' attribute XElement nextStateElem = new XElement(XMLFactory.KSTATE_ELEM); nextStatesElem.Add(nextStateElem); // [SC] add 'TwoA/KStructure/KSRank/KState/NextStates/KState@xsd:idref' attribute XAttribute idrefAttr = new XAttribute(XMLFactory.IDREF_ATTR, "" + nextState.Id); nextStateElem.Add(idrefAttr); } } } } else { Log(Severity.Warning, "Knowledge structure is missing while transforming KStructure object into XML format."); } return(doc); }