/// <summary> /// Determines whether the specified <see cref="DecisionRule"/> is equal to this instance. /// </summary> /// /// <param name="other">The <see cref="DecisionRule"/> to compare with this instance.</param> /// /// <returns> /// <c>true</c> if the specified <see cref="DecisionRule"/> /// is equal to this instance; otherwise, <c>false</c>. /// </returns> /// public bool Equals(DecisionRule other) { if ((object)other == null) { return(false); } return(this.Output == other.output && this.Antecedents.SetEquals(other.Antecedents)); }
/// <summary> /// Compares this instance to another <see cref="DecisionRule"/>. /// </summary> /// public int CompareTo(DecisionRule other) { int order = this.Output.CompareTo(other.Output); if (order == 0) { return(this.Antecedents.Count.CompareTo(other.Antecedents.Count)); } return(order); }
/// <summary> /// Gets whether this rule and another rule have /// the same antecedents but different outputs. /// </summary> /// /// <param name="rule"></param> /// /// <returns>True if the two rules are contradictory; /// false otherwise.</returns> /// public bool IsInconsistentWith(DecisionRule rule) { return(Antecedents.SetEquals(rule.Antecedents) && Output != rule.Output); }
/// <summary> /// Computes the reduction algorithm. /// </summary> /// /// <param name="inputs">A set of training inputs.</param> /// <param name="outputs">The outputs corresponding to each of the inputs.</param> /// /// <returns>The average error after the reduction.</returns> /// public double Compute(double[][] inputs, int[] outputs) { int samples = outputs.Length; bool[] actual = new bool[samples]; bool[] expected = new bool[samples]; DecisionRule[] list = decisionList.ToArray(); var antecedents = new HashSet <Antecedent>(); foreach (DecisionRule rule in list) { foreach (Antecedent antecedent in rule) { antecedents.Add(antecedent); } } // 1. Eliminate unnecessary antecedents for (int y = 0; y < decisionList.OutputClasses; y++) { for (int i = 0; i < outputs.Length; i++) { expected[i] = outputs[i] == y; } var unnecessary = new HashSet <Antecedent>(); /*foreach (var rule in list) * { * if (rule.Output != y) * continue; */ foreach (var antecedent in antecedents) { for (int i = 0; i < inputs.Length; i++) { actual[i] = antecedent.Match(inputs[i]); } if (CanEliminate(actual, expected)) { unnecessary.Add(antecedent); } } //} foreach (var antecedent in unnecessary) { foreach (var rule in list) { if (rule.Output == y) { rule.Antecedents.Remove(antecedent); } } } } bool[][] matches = new bool[list.Length][]; int[] counts = new int[list.Length]; for (int i = 0; i < matches.Length; i++) { DecisionRule rule = list[i]; matches[i] = new bool[outputs.Length]; for (int j = 0; j < inputs.Length; j++) { matches[i][j] = rule.Match(inputs[j]); if (matches[i][j]) { counts[i]++; } } } // double start = computeError(inputs, outputs, list); for (int i = 0; i < list.Length; i++) { if (list[i] == null) { continue; } for (int j = 0; j < list.Length; j++) { if (list[i] == null) { break; } if (list[j] == null) { continue; } if (list[i].IsInconsistentWith(list[j])) { if (counts[i] > counts[j]) { list[j] = null; counts[j] = 0; } else { list[i] = null; counts[i] = 0; } } } } list = list.Distinct(allowNulls: false); List <DecisionRule> newList = new List <DecisionRule>(list); // double middle = computeError(inputs, outputs, list); // 2. Eliminate redundant rules from the set for (int y = 0; y < decisionList.OutputClasses; y++) { for (int i = 0; i < outputs.Length; i++) { expected[i] = outputs[i] == y; } var unnecessary = new HashSet <DecisionRule>(); foreach (var rule in newList) { if (rule.Output != y) { continue; } for (int i = 0; i < inputs.Length; i++) { actual[i] = rule.Match(inputs[i]); } if (CanEliminate(actual, expected)) { unnecessary.Add(rule); } } foreach (var rule in unnecessary) { newList.Remove(rule); } } // double final = computeError(inputs, outputs, newList); decisionList.Clear(); decisionList.AddRange(newList); // Compute new decision error double newError = ComputeError(inputs, outputs); return(newError); }