/* * this method is to create virtual nodes where a certain node has 'AND' or 'MANDATORY_AND', and 'OR' children at the same time. * when a virtual node is created, all 'AND' children should be connected to the virtual node as 'AND' children * and the virtual node should be a 'OR' child of the original parent node */ public Dictionary <string, Node> HandlingVirtualNode(List <Dependency> dependencyList) { Dictionary <string, Node> virtualNodeMap = new Dictionary <string, Node>(); nodeSet.GetNodeMap().Values.ToList().ForEach((node) => { virtualNodeMap.Add(node.GetNodeName(), node); List <Dependency> dpList = dependencyList.Where(dp => node.GetNodeName().Equals(dp.GetParentNode().GetNodeName())).ToList(); /* * need to handle Mandatory, optionally, possibly NodeOptions */ int and = 0; int mandatoryAnd = 0; int or = 0; if (dpList.Count != 0) { foreach (Dependency dp in dpList) //can this for each loop be converted to dpList.stream().forEachOrdered() ? { if ((dp.GetDependencyType() & DependencyType.GetAnd()) == DependencyType.GetAnd()) { and++; if (dp.GetDependencyType() == (DependencyType.GetMandatory() | DependencyType.GetAnd())) { mandatoryAnd++; } } else if ((dp.GetDependencyType() & DependencyType.GetOr()) == DependencyType.GetOr()) { or++; } } bool hasAndOr = (and > 0 && or > 0) ? true : false; if (hasAndOr) { string parentNodeOfVirtualNodeName = node.GetNodeName(); Node virtualNode = new ValueConclusionLine("VirtualNode-" + parentNodeOfVirtualNodeName, Tokenizer.GetTokens("VirtualNode-" + parentNodeOfVirtualNodeName)); this.nodeSet.GetNodeIdMap().Add(virtualNode.GetNodeId(), "VirtualNode-" + parentNodeOfVirtualNodeName); virtualNodeMap.Add("VirtualNode-" + parentNodeOfVirtualNodeName, virtualNode); if (mandatoryAnd > 0) { dependencyList.Add(new Dependency(node, virtualNode, (DependencyType.GetMandatory() | DependencyType.GetOr()))); } else { dependencyList.Add(new Dependency(node, virtualNode, DependencyType.GetOr())); } dpList.Where(dp => dp.GetDependencyType() == DependencyType.GetAnd() || dp.GetDependencyType() == (DependencyType.GetMandatory() | DependencyType.GetAnd())) .ToList().ForEach(dp => dp.SetParentNode(virtualNode)); } } }); return(virtualNodeMap); }
public void HandleParent(string parentText, int lineNumber) { Node data = nodeSet.GetNodeMap().ContainsKey(parentText)?nodeSet.GetNodeMap()[parentText]:null; if (data == null) { Tokens tokens = Tokenizer.GetTokens(parentText); Regex[] matchPatterns = { META_PATTERN_MATCHER, VALUE_MATCHER, EXPRESSION_CONCLUSION_MATCHER, WARNING_MATCHER }; for (int i = 0; i < matchPatterns.Length; i++) { //matcher = Regex.Match(tokens.tokensString, matchPatterns[i]); Regex regex = matchPatterns[i]; Match match = regex.Match(tokens.tokensString); if (match.Success) { string variableName; Node tempNode; List <string> possibleParentNodeKeyList; switch (i) { case 3: //warningMatcher case HandleWarning(parentText); break; case 0: //metaMatcher case data = new MetadataLine(parentText, tokens); if (data.GetFactValue().GetFactValueType() != FactValueType.LIST && FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; case 1: //valueConclusionLine case data = new ValueConclusionLine(parentText, tokens); if (match.Groups[2] != null || (tokens.tokensString.Equals("L") || tokens.tokensString.Equals("LM") || tokens.tokensString.Equals("ML") || tokens.tokensString.Equals("M"))) { variableName = data.GetVariableName(); tempNode = data; /* * following lines are to look for any nodes having a its nodeName with any operators due to the reason that * the node could be used to define a node previously used as a child node for other nodes */ possibleParentNodeKeyList = nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "(.+)?(\\s[<>=]+\\s?)?(" + variableName + ")(\\s?[<>=]+)*(?!(.*(IS)))(.*(IS IN LIST).*)*").Success).ToList(); if (possibleParentNodeKeyList.Count != 0) { possibleParentNodeKeyList.ForEach(item => { this.dependencyList.Add(new Dependency(nodeSet.GetNodeMap()[item], tempNode, DependencyType.GetOr())); //Dependency Type :OR }); } } if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; case 2: //exprConclusionMatcher case data = new ExprConclusionLine(parentText, tokens); variableName = data.GetVariableName(); tempNode = data; /* * following lines are to look for any nodes having a its nodeName with any operators due to the reason that * the exprConclusion node could be used to define another node as a child node for other nodes if the variableName of exprConclusion node is mentioned somewhere else. * However, it is excluding nodes having 'IS' keyword because if it has the keyword then it should have child nodes to define the node otherwise the entire rule set has NOT been written in correct way */ possibleParentNodeKeyList = nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "(.+)?(\\s[<>=]+\\s?)?(" + variableName + ")(\\s?[<>=]+)*(?!(.*(IS)))(.*(IS IN LIST).*)*").Success).ToList(); if (possibleParentNodeKeyList.Count != 0) { possibleParentNodeKeyList.ForEach(item => { this.dependencyList.Add(new Dependency(nodeSet.GetNodeMap()[item], tempNode, DependencyType.GetOr())); //Dependency Type :OR }); } if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; default: HandleWarning(parentText); break; } data.SetNodeLine(lineNumber); if (data.GetLineType().Equals(LineType.META)) { if (((MetadataLine)data).GetMetaType().Equals(MetaType.INPUT)) { this.nodeSet.GetInputMap().Add(data.GetVariableName(), data.GetFactValue()); } else if (((MetadataLine)data).GetMetaType().Equals(MetaType.FIXED)) { this.nodeSet.GetFactMap().Add(data.GetVariableName(), data.GetFactValue()); } } else { this.nodeSet.GetNodeMap().Add(data.GetNodeName(), data); this.nodeSet.GetNodeIdMap().Add(data.GetNodeId(), data.GetNodeName()); } break; } } } }
public void HandleChild(string parentText, string childText, string firstKeywordsGroup, int lineNumber) { /* * the reason for using '*' at the last group of pattern within comparison is that * the last group contains No, Da, De, Ha, Url, Id. * In order to track more than one character within the square bracket of last group '*'(Matches 0 or more occurrences of the preceding expression) needs to be used. * */ int dependencyType = 0; // is 'ITEM' child line if (Regex.Match(childText, "(ITEM)(.*)").Success) { if (!Regex.Match(parentText, "(.*)(AS LIST)").Success) { HandleWarning(childText); return; } // is an indented item child childText = childText.Remove(childText.IndexOf("ITEM", StringComparison.CurrentCulture), "ITEM".Length).Trim(); MetaType?metaType = null; if (Regex.Match(parentText, "^(INPUT)(.*)").Success) { metaType = MetaType.INPUT; } else if (Regex.Match(parentText, "^(FIXED)(.*)").Success) { metaType = MetaType.FIXED; } HandleListItem(parentText, childText, metaType); } else // is 'A-statement', 'A IS B', 'A <= B', or 'A IS CALC (B * C)' child line { if (Regex.Match(firstKeywordsGroup, "^(AND\\s?)(.*)").Success) { dependencyType = HandleNotKnownManOptPos(firstKeywordsGroup, DependencyType.GetAnd()); // 8-AND | 1-KNOWN? 2-NOT? 64-MANDATORY? 32-OPTIONALLY? 16-POSSIBLY? } else if (Regex.Match(firstKeywordsGroup, "^(OR\\s?)(.*)").Success) { dependencyType = HandleNotKnownManOptPos(firstKeywordsGroup, DependencyType.GetOr()); // 4-OR | 1-KNOWN? 2-NOT? 64-MANDATORY? 32-OPTIONALLY? 16-POSSIBLY? } else if (Regex.Match(firstKeywordsGroup, "^(WANTS)").Success) { dependencyType = DependencyType.GetOr(); // 4-OR } else if (Regex.Match(firstKeywordsGroup, "^(NEEDS)").Success) { dependencyType = DependencyType.GetMandatory() | DependencyType.GetAnd(); // 8-AND | 64-MANDATORY } /* * the keyword of 'AND' or 'OR' should be removed individually. * it should NOT be removed by using firstToken string in Tokens.tokensList.get(0) * because firstToken string may have something else. * (e.g. string: 'AND NOT ALL Males' name should sound Male', then Token string will be 'UMLM', and 'U' contains 'AND NOT ALL'. * so if we used 'firstToken string' to remove 'AND' in this case as 'string.replace(firstTokenString)' * then it will remove 'AND NOT ALL' even we only need to remove 'AND' * */ Node data = null; nodeSet.GetNodeMap().TryGetValue(childText, out data); Tokens tokens = Tokenizer.GetTokens(childText); if (data == null) { Regex[] matchPatterns = { VALUE_MATCHER, COMPARISON_MATCHER, ITERATE_MATCHER, EXPRESSION_CONCLUSION_MATCHER, WARNING_MATCHER }; Node tempNode; List <string> possibleChildNodeKeyList; for (int i = 0; i < matchPatterns.Length; i++) { Regex regex = matchPatterns[i]; Match match = regex.Match(tokens.tokensString); if (match.Success) { switch (i) { case 4: // warningMatcher case HandleWarning(childText); break; case 0: // valueConclusionMatcher case data = new ValueConclusionLine(childText, tokens); tempNode = data; possibleChildNodeKeyList = nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + tempNode.GetVariableName() + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList(); if (possibleChildNodeKeyList.Count != 0) { possibleChildNodeKeyList.ForEach(item => { this.dependencyList.Add(new Dependency(tempNode, nodeSet.GetNodeMap()[item], DependencyType.GetOr())); //Dependency Type :OR }); } if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; case 1: // comparisonMatcher case data = new ComparisonLine(childText, tokens); FactValueType rhsType = ((ComparisonLine)data).GetRHS().GetFactValueType(); string rhsString = FactValue.GetValueInString(((ComparisonLine)data).GetRHS().GetFactValueType(), ((ComparisonLine)data).GetRHS()); string lhsString = ((ComparisonLine)data).GetLHS(); tempNode = data; possibleChildNodeKeyList = rhsType.Equals(FactValueType.STRING) ? nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + lhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success || Regex.Match(key, "^(" + rhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList() : nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + lhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList(); if (possibleChildNodeKeyList.Count != 0) { possibleChildNodeKeyList.ForEach(item => { this.dependencyList.Add(new Dependency(tempNode, nodeSet.GetNodeMap()[item], DependencyType.GetOr())); //Dependency Type :OR }); } if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; case 2: // iteratenMatcher case data = new IterateLine(childText, tokens); if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; case 3: //exprConclusionMatcher case data = new ExprConclusionLine(childText, tokens); /* * In this case, there is no mechanism to find possible parent nodes. * I have brought 'local variable' concept for this case due to it may massed up with structuring node dependency tree with topological sort * If ExprConclusion node is used as a child, then it means that this node is a local node which has to be strictly bound to its parent node only. */ if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING")) { HandleWarning(parentText); } break; } data.SetNodeLine(lineNumber); this.nodeSet.GetNodeMap().Add(data.GetNodeName(), data); this.nodeSet.GetNodeIdMap().Add(data.GetNodeId(), data.GetNodeName()); break; } } } this.dependencyList.Add(new Dependency(this.nodeSet.GetNode(parentText), data, dependencyType)); } }
/* * The idea of this method is to visit a rule that could get a result of parent rule of the rule as quick as it can be * for instance, if a 'OR' child rule is 'TRUE' then the parent rule is 'TRUE', * and if a 'AND' child rule is 'FALSE' then the parent rule is 'FALSE'. * AS result, visit more likely true 'OR' rule or more likely false 'AND' rule to determine a parent rule as fast as we can */ public static List <Node> Visit(Node node, List <Node> sortedList, Dictionary <string, Record> recordMapOfNodes, Dictionary <string, Node> nodeMap, Dictionary <int?, string> nodeIdMap, List <Node> visitedNodeList, int[,] dependencyMatrix) { if (node != null) { sortedList.Add(node); int nodeId = node.GetNodeId(); int orDependencyType = DependencyType.GetOr(); int andDependencyType = DependencyType.GetAnd(); List <int> dependencyMatrixAsList = new List <int>(); Enumerable.Range(0, dependencyMatrix.GetLength(1)).ToList().ForEach((index) => dependencyMatrixAsList.Add(dependencyMatrix[nodeId, index])); List <int> orOutDependency = (System.Collections.Generic.List <int>)Enumerable.Range(0, dependencyMatrixAsList.Count) .Where(index => (dependencyMatrixAsList[index] & orDependencyType) == orDependencyType); List <int> andOutDependency = (System.Collections.Generic.List <int>)Enumerable.Range(0, dependencyMatrixAsList.Count) .Where(index => (dependencyMatrixAsList[index] & andDependencyType) == andDependencyType); if (orOutDependency.Count != 0 || andOutDependency.Count != 0) { List <Node> childRuleList = new List <Node>(); Enumerable.Range(0, dependencyMatrixAsList.Count).ToList() .Where(childIndex => dependencyMatrixAsList[childIndex] != 0) .ToList() .ForEach(item => childRuleList.Add(nodeMap[nodeIdMap[item]])); if (orOutDependency.Count != 0 && andOutDependency.Count == 0) { while (childRuleList.Count != 0) { /* * the reason for selecting an option having more number of 'yes' is as follows * if it is 'OR' rule and it is 'TRUE' then it is the shortest path, and ignore other 'OR' rules * Therefore, looking for more likely 'TRUE' rule would be the shortest one rather than * looking for more likely 'FALSE' rule in terms of processing time */ Node theMostPositive = FindTheMostPositive(childRuleList, recordMapOfNodes, dependencyMatrixAsList); // Node theMostPositive = findTheMostPositive(childRuleList, recordMapOfNodes); if (!visitedNodeList.Contains(theMostPositive)) { visitedNodeList.Add(theMostPositive); sortedList = Visit(theMostPositive, sortedList, recordMapOfNodes, nodeMap, nodeIdMap, visitedNodeList, dependencyMatrix); } } } else { if (orOutDependency.Count == 0 && andOutDependency.Count != 0) { /* * the reason for selecting an option having more number of 'yes' is as follows * if it is 'AND' rule and it is 'FALSE' then it is the shortest path, and ignore other 'AND' rules * Therefore, looking for more likely 'FALSE' rule would be the shortest one rather than * looking for more likely 'TRUE' rule in terms of processing time */ while (childRuleList.Count != 0) { Node theMostNegative = FindTheMostNegative(childRuleList, recordMapOfNodes, dependencyMatrixAsList); // Node theMostNegative = findTheMostNegative(childRuleList, recordMapOfNodes); if (!visitedNodeList.Contains(theMostNegative)) { visitedNodeList.Add(theMostNegative); sortedList = Visit(theMostNegative, sortedList, recordMapOfNodes, nodeMap, nodeIdMap, visitedNodeList, dependencyMatrix); } } } } } } return(sortedList); }