/// <summary> /// Checks whether the given <see cref="MathProgram" /> computes a value that is consistently equivalent to that /// computed /// by another program according to some margin. The method works by substituting the variables in both programs' /// expressions by random values for a certain number of trials. In each trial, the difference between the values /// computed by both programs is calculated. If the difference is less than a given margin for all the trials, then the /// programs are considered to be value-equivalent. /// </summary> /// <param name="program">The first program that we want to test.</param> /// <param name="other">The second program that we want to test.</param> /// <param name="margin"> /// The margin used to compare against the difference of values computed by both expressions in each /// trial. /// </param> /// <param name="numTrials">The number of trials used to discern whether the given programs are equivalent.</param> /// <returns><c>True</c> if the given programs are considered to be value-equivalent, <c>False</c> otherwise.</returns> public static bool IsValueEquivalent( this ITreeProgram <double> program, ITreeProgram <double> other, double margin = DEFAULT_MARGIN, uint numTrials = DEFAULT_NUM_TRIALS) { // checks null if (program == null || other == null) { return(false); } // checks equivalence if (program.Equals(other)) { return(true); } // checks expression or constant equivalence after simplification program = program.Simplify(); other = other.Simplify(); if (program.Equals(other) || program.IsConstant() && other.IsConstant() && Math.Abs(program.Compute() - other.Compute()) < margin) { return(true); } // gets RMSE by replacing the values of the variables in some number of trials return(program.GetValueRmsd(other, numTrials) <= margin); }
/// <summary> /// Gets the root-mean-square deviation (RMSD) between the values computed for the given programs. The method works by /// substituting the variables in both programs' expressions by random values for a certain number of trials. In each /// trial, the square of the difference between the values computed by both programs is calculated. /// </summary> /// <param name="program">The first program that we want to test.</param> /// <param name="other">The second program that we want to test.</param> /// <param name="numTrials">The number of trials used to compute the squared difference.</param> /// <returns>The RMSD between the several values computed for the given programs.</returns> public static double GetValueRmsd( this ITreeProgram <double> program, ITreeProgram <double> other, uint numTrials = DEFAULT_NUM_TRIALS) { // checks null if (program == null || other == null) { return(double.MaxValue); } // checks expression or constant equivalence after simplification program = program.Simplify(); other = other.Simplify(); if (program.Equals(other) || program.IsConstant() && other.IsConstant()) { return(Math.Abs(program.Compute() - other.Compute())); } // replaces variables of each expression by custom variables var customVariables = new Dictionary <Variable, Variable>(); program = ReplaceVariables(program, customVariables); other = ReplaceVariables(other, customVariables); if (customVariables.Count == 0) { return(double.MaxValue); } // gets random values for each variable var customVariablesValues = customVariables.Values.ToDictionary( variable => variable, variable => GetTrialRandomNumbers(numTrials, variable.Range)); // runs a batch of trials var squareDiffSum = 0d; for (var i = 0; i < numTrials; i++) { // replaces the value of each variable by a random number foreach (var customVariablesValue in customVariablesValues) { customVariablesValue.Key.Value = customVariablesValue.Value[i]; } // computes difference of the resulting values of the expressions var prog1Value = program.Compute(); var prog2Value = other.Compute(); var diff = prog1Value.Equals(prog2Value) ? 0 : prog1Value - prog2Value; squareDiffSum += diff * diff; } // returns RMSD return(Math.Sqrt(squareDiffSum / numTrials)); }
/// <summary> /// Computes a <see cref="Range" /> representing the minimum and maximum values that a given <see cref="MathProgram" /> /// can compute, as dictated by its sub-programs. /// </summary> /// <param name="program">The program whose range we want to compute.</param> /// <returns>The range of the given program.</returns> public static Range GetRange(this ITreeProgram <double> program) { // checks for constant value if (program.IsConstant()) { var value = program.Compute(); return(new Range(value, value)); } // checks for variable if (program is Variable) { return(((Variable)program).Range); } // collects info on ranges of all children var childrenRanges = new List <IEnumerable <double> >(); foreach (var child in program.Input) { var childRange = GetRange(child); childrenRanges.Add(new[] { childRange.Min, childRange.Max }); } // gets all combinations between children ranges var min = double.MaxValue; var max = double.MinValue; var allRangeCombinations = childrenRanges.GetAllCombinations(); foreach (var rangeCombination in allRangeCombinations) { // builds new program by replacing children with constant values (range min or max) var children = new ITreeProgram <double> [rangeCombination.Count]; for (var i = 0; i < rangeCombination.Count; i++) { children[i] = new Constant(rangeCombination[i]); } var newElem = program.CreateNew(children); // checks min and max values from new prog value var val = newElem.Compute(); min = Math.Min(min, val); max = Math.Max(max, val); } return(new Range(min, max)); }
/// <summary> /// Verifies whether the <see cref="MathProgram" /> is a constant value, i.e., whether all its descendant leaf /// programs are instances of <see cref="Constant" />, and whether the associated value equals to /// <paramref name="val" />. /// </summary> /// <returns> /// <c>true</c>, if program is a constant and its value equals <paramref name="val" />, <c>false</c> /// otherwise. /// </returns> /// <param name="program">The program to verify whether it is a constant.</param> /// <param name="val">The value to test for the program.</param> public static bool EqualsConstant(this ITreeProgram <double> program, double val) => program.IsConstant() && program.Compute().Equals(val);