/// <summary> /// Checks whether this program is equal to another. /// </summary> /// <param name="other">The other program to check for equality.</param> /// <returns> /// <c>true</c> if the objects are the same or have the same <see cref="Label" /> and their <see cref="Input" /> /// sequence is the same. /// </returns> public bool Equals(MathProgram other) { return(!(other is null) && (ReferenceEquals(this, other) || this.GetType() == other.GetType() && this._hashCode == other._hashCode && string.Equals(this.Label, other.Label) && this.Input.SequenceEqual(other.Input))); }
/// <summary> /// Simplifies the expression of the given <see cref="MathProgram" /> by returning a sub-combination whose fitness is /// approximately equal to that of the original program by a margin of <paramref name="margin" />, and whose /// expression is naturally simpler, i.e., has fewer sub-programs. /// </summary> /// <returns>An program corresponding to a simplification of the given program.</returns> /// <param name="program">The program we want to simplify.</param> /// <param name="fitnessFunction">The fitness function used to determine equivalence.</param> /// <param name="margin"> /// The acceptable difference between the fitness of the given program and that of a simplified program for them to be /// considered equivalent. /// </param> public static ITreeProgram <double> Simplify( this MathProgram program, IFitnessFunction <MathProgram> fitnessFunction, double margin = DEFAULT_MARGIN) { // gets original program's fitness and count var simplified = program; var fitness = fitnessFunction.Evaluate(program); var length = program.Length; // first replaces all sub-programs by infinity and NaN recursively var consts = new HashSet <Constant> { new Constant(double.NegativeInfinity), new Constant(double.NaN), new Constant(double.PositiveInfinity) }; bool simplificationFound; do { simplificationFound = false; var simpLength = simplified.Length; for (var i = 0u; i < simpLength && !simplificationFound; i++) { if (consts.Contains(simplified.ProgramAt(i))) { continue; } foreach (var constant in consts) { var prog = (MathProgram)simplified.Replace(i, constant); var fit = fitnessFunction.Evaluate(prog); var progLength = prog.Length; if (Math.Abs(fit - fitness) < margin && progLength <= length) { simplified = prog; length = progLength; simplificationFound = true; break; } } } } while (simplificationFound); // then gets all sub-combinations of the simplified program var alternatives = simplified.GetSubCombinations(); foreach (MathProgram subComb in alternatives) { var subFit = fitnessFunction.Evaluate(subComb); var subCombLength = subComb.Length; //checks their fitness and count if (Math.Abs(subFit - fitness) < margin && subCombLength < length) { simplified = subComb; length = subCombLength; } } return(simplified); }