// Main function which does all the steps AQ11 takes to generate rules public Rule ruleInference() { // AQ11 inputs // Positive examples E1 List <Example> positiveExamples = examples.FindAll(example => example.groupClass == groupClass); // Negative examples E2 List <Example> negativeExamples = examples.Except(positiveExamples).ToList(); // Data member for the most specific wrappers ei/ej(positive vs negative example) List <List <Disjunction> > firstLevelClausules = new List <List <Disjunction> >(); // Data member for the more general wrappers ei/E2(positive example vs negative class) List <Conjunction> secondLevelClausules = new List <Conjunction>(); // Data member indicting which examples were already covered by generated wrappers and thus // no longer need to be analyzed List <int> skipList = new List <int>(); // AQ11 runs through all positive examples for (int i = 0; i < positiveExamples.Count; i++) { // Replaces "remove all positive examples covered by any ei/E2 wrapper" to avoid // problems with modifying the list that is currently being iterated if (skipList.Exists(num => num == i)) { continue; } Example pos = positiveExamples[i]; firstLevelClausules.Add(new List <Disjunction>()); // Generate ei/ej wrapper for every negative example for (int j = 0; j < negativeExamples.Count; j++) { Example neg = negativeExamples[j]; // Each wrapper consists of a disjunction of inequalities List <LogicalArgument> ineqs = new List <LogicalArgument>(); for (int k = 0; k < pos.attributes.Count; k++) { // Inequality for each separate attribute is generated if the positive and negative // examples do not share the same value in it if (pos.attributes[k].value != neg.attributes[k].value) { Variable var = new Variable(pos.attributes[k].name); Constant cons = new Constant(neg.attributes[k].value); Inequality ineq = new Inequality(var, cons); ineqs.Add(ineq); } } // Disjunction is created for all generated inequalities and added to correct data member Disjunction disj = new Disjunction(ineqs); firstLevelClausules[firstLevelClausules.Count - 1].Add(disj); } // Generates ei/E2 wrapper for the current positive example as conjunction of all // ei/ej wrappers and by applying the absorb rule secondLevelClausules.Add(applyAbsorbRule(firstLevelClausules[firstLevelClausules.Count - 1])); // Using the newly generated ei/E2 wrapper, skip list is updated to include positive examples // covered by it skipList.AddRange(skipCoveredExamples(secondLevelClausules[secondLevelClausules.Count - 1], positiveExamples, i)); } // All ei/E2 wrappers are merged using disjunctions in a final rule wrapper E1/E2 Rule rule = new Rule(secondLevelClausules, groupClass); return(rule); }
private List <LogicalArgument> equalitiesInference(List <LogicalArgument> result) { // Builds an attribute map containing: // 1.) names of all attributes // 2.) all possible values for each attribute present in the training set AttributeValueMap[] maps = new AttributeValueMap[examples[0].attributes.Count]; for (int i = 0; i < maps.Length; i++) { // Uses the first example as a map prototype for the attribute names maps[i] = new AttributeValueMap(examples[0].attributes[i].name, examples[0].attributes[i].type); } foreach (Example ex in examples) { // Runs through all examples and saves their unique attribute values in appropriate maps for (int i = 0; i < ex.attributes.Count; i++) { Attribute atr = ex.attributes[i]; if (maps[i].values.Exists(val => val == atr.value) == false) { maps[i].values.Add(atr.value); } } } // Builds an attribute map containing: // 1.) names of all attributes present in the grouped up unabsorbed disjuncts // 2.) values of the attributes present in the unabsorbed inequalities List <AttributeValueMap> resultMap = new List <AttributeValueMap>(); foreach (LogicalArgument arg in result) { if (arg.GetType().Name == "Inequality") { Inequality ineq = (Inequality)arg; if (ineq.firstArgument.GetType().Name == "Variable") { // Variable name represents the attribute name Variable var = (Variable)ineq.firstArgument; // Constant name represents the attribute value Constant cons = (Constant)ineq.secondArgument; bool mapFound = false; foreach (AttributeValueMap map in resultMap) { // If attribute map is found for the given name // it adds its value if its not yet listed in the map if (map.name == var.name) { foreach (string value in cons.valueSet) { if (map.values.Exists(val => val == value) == false) { mapFound = true; map.values.Add(value); } } } } // If no map is found for attribute of the given name if (!(mapFound)) { // New map is created using data from the full attribute map generated from training set AttributeType type = maps.ToList().Find(m => m.name == var.name).type; AttributeValueMap map = new AttributeValueMap(var.name, type); map.values.AddRange(cons.valueSet); resultMap.Add(map); } } } } // Inequalities are changed to equalities for better readability List <LogicalArgument> output = new List <LogicalArgument>(); foreach (AttributeValueMap map in resultMap) { AttributeValueMap candidate = maps.ToList().Find(m => m.name == map.name); if (candidate != null) { Variable var = new Variable(map.name); List <string> missingValues = new List <string>(); // Aquires all values allowed by the inequality from the attributemap foreach (string value in candidate.values) { if (map.values.Exists(val => val == value) == false) { missingValues.Add(value); } } // Builds equation from the missing values and adds it to the final output Constant cons = new Constant(missingValues); Equality eq = new Equality(var, cons); output.Add(eq); } } return(output); }