Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        /// <summary>
        ///     Gets a new copy of <paramref name="program" /> where all sub-programs that are equal to
        ///     <paramref name="oldSubProgram" /> are replaced by <paramref name="newSubProgram" />.
        /// </summary>
        /// <param name="program">The root program to copy and search for the given sub-program .</param>
        /// <param name="oldSubProgram">The sub-program we want to replace.</param>
        /// <param name="newSubProgram">The new sub-program to replace the given one.</param>
        /// <returns>
        ///     A copy of the program with the given descendant replaced by the new program. If the given program is equal to the
        ///     sub-program we want to replace, then the replacement is returned. If the given sub-program is not found, a copy of
        ///     the original program is returned, or <c>null</c> if the program is <c>null</c>.
        /// </returns>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static ITreeProgram <TOutput> Replace <TOutput>(
            this ITreeProgram <TOutput> program, ITreeProgram <TOutput> oldSubProgram,
            ITreeProgram <TOutput> newSubProgram)
        {
            if (program == null || oldSubProgram == null || newSubProgram == null)
            {
                return(program);
            }

            // checks if program is equal, return replacement
            if (program.Equals(oldSubProgram))
            {
                return(newSubProgram);
            }

            // replaces children recursively and creates a new program
            if (program.Input == null || program.Input.Count == 0)
            {
                return(program);
            }
            var children = new ITreeProgram <TOutput> [program.Input.Count];

            for (var i = 0; i < program.Input.Count; i++)
            {
                children[i] = Replace(program.Input[i], oldSubProgram, newSubProgram);
            }
            return(program.CreateNew(children));
        }
Exemplo n.º 3
0
        /// <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));
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Checks whether a given <see cref="ITreeProgram{TOutput}" /> is a sub-program of another
        ///     <see cref="ITreeProgram{TOutput}" />.
        ///     A sub-program is an program that is a descendant of a given program.
        /// </summary>
        /// <param name="program">The program we want to know if it is a sub-program.</param>
        /// <param name="other">The program for which to look for a descendant equal to the given program.</param>
        /// <returns><c>true</c>, if the program is a descendant of the other program, <c>false</c> otherwise.</returns>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static bool IsSubProgramOf <TOutput>(this ITreeProgram <TOutput> program, ITreeProgram <TOutput> other)
        {
            // checks prog
            if (program == null || other == null ||
                program.Length >= other.Length || other.Input?.Count == 0)
            {
                return(false);
            }

            // search the descendants for the given program
            return(other.Input != null &&
                   other.Input.Any(child => program.Equals(child) || program.IsSubProgramOf(child)));
        }
Exemplo n.º 5
0
        /// <summary>
        ///     Checks whether a given <see cref="ITreeProgram{TOutput}" /> contains the given sub-program.
        ///     A sub-program is an program that is a descendant of a given program.
        /// </summary>
        /// <returns><c>true</c>, if the given program is a descendant of the given program, <c>false</c> otherwise.</returns>
        /// <param name="program">The program for which to look for a descendant equal to the given program.</param>
        /// <param name="other">The program we want to know if it is a sub-program.</param>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static bool ContainsSubElement <TOutput>(
            this ITreeProgram <TOutput> program, ITreeProgram <TOutput> other)

        {
            // checks prog
            if (program == null || other == null ||
                program.Length <= other.Length || program.Input?.Count == 0)
            {
                return(false);
            }

            // search the descendants for the given program
            return(program.Input != null &&
                   program.Input.Any(child => other.Equals(child) || child.ContainsSubElement(other)));
        }
Exemplo n.º 6
0
        private static double Calculate(ITreeProgram <TOutput> prog1, ITreeProgram <TOutput> prog2)
        {
            // checks simple cases
            if (prog1 == null || prog2 == null)
            {
                return(0);
            }
            if (prog1.Equals(prog2))
            {
                return(1);
            }

            // replace all common sub-programs by weighted variables
            var ignorePrograms = new HashSet <ITreeProgram <TOutput> >();
            var minCount       = Math.Min(prog1.Length, prog2.Length);

            for (var i = 0; i < minCount; i++)
            {
                var largestCommon = GetLargestCommon(ref prog1, ref prog2, ignorePrograms);
                if (largestCommon == null || largestCommon.Length < 2)
                {
                    break;
                }
                var newSubProgram = new WeightedVariable(largestCommon.Expression, largestCommon.Length);
                prog1 = prog1.Replace(largestCommon, newSubProgram);
                prog2 = prog2.Replace(largestCommon, newSubProgram);
                ignorePrograms.Add(newSubProgram);
            }

            // gets sub-programs
            var subProgs1 = new List <ITreeProgram <TOutput> > {
                prog1
            };

            subProgs1.AddRange(prog1.GetSubPrograms());
            var subProgs2 = new List <ITreeProgram <TOutput> > {
                prog2
            };

            subProgs2.AddRange(prog2.GetSubPrograms());

            // tries to align both trees in all possible ways
            var minRelCost = double.MaxValue;

            for (var i = 0u; i < prog1.Length; i++)
            {
                for (var j = 0u; j < prog2.Length; j++)
                {
                    // alignment is determined by the starting indexes of both trees
                    var idx1 = i;
                    var idx2 = j;

                    // adds cost of having to add previous nodes (shifting/alignment cost)
                    var cost      = i + j;
                    var totalCost = cost;

                    // gets edit cost between sub-programs
                    GetEditCost(subProgs1, subProgs2, ref idx1, ref idx2, ref cost, ref totalCost);

                    // checks cost of having to add remaining nodes
                    var remainder = prog1.Length - idx1 + prog2.Length - idx2 - 2;
                    cost      += remainder;
                    totalCost += remainder;
                    var relCost = (double)cost / totalCost;

                    // updates min relative cost
                    if (relCost < minRelCost)
                    {
                        minRelCost = relCost;
                    }
                }
            }

            return(1d - minRelCost);
        }