Beispiel #1
0
        /// <inheritdoc />
        public override ITreeProgram <double> Simplify()
        {
            // if its a constant value, just return a constant with that value
            if (this.IsConstant())
            {
                return(new Constant(this.Compute()));
            }

            // otherwise first tries to simplify children
            var input = new ITreeProgram <double> [this.Input.Count];

            for (var i = 0; i < this.Input.Count; i++)
            {
                input[i] = this.Input[i].Simplify();
            }

            // if operands are equal return the first
            if (input[0].Equals(input[1]))
            {
                return(input[0]);
            }

            // check whether one of operands is maximum and return the other
            if (input[0].EqualsConstant(double.MaxValue) || input[0].EqualsConstant(double.PositiveInfinity))
            {
                return(input[1]);
            }
            if (input[1].EqualsConstant(double.MaxValue) || input[1].EqualsConstant(double.PositiveInfinity))
            {
                return(input[0]);
            }

            return(this.CreateNew(input));
        }
Beispiel #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));
        }
Beispiel #3
0
        private static void GetCommonRegionIndexes <TOutput>(
            this ITreeProgram <TOutput> program, ITreeProgram <TOutput> otherProgram, IDictionary <uint, uint> indexes,
            ref uint idx1, ref uint idx2)
        {
            // add the corresponding (common region) indexes
            indexes.Add(idx1, idx2);

            // check if children differ (different sub-structure)
            if (program?.Input == null || otherProgram?.Input == null ||
                program.Input.Count != otherProgram.Input.Count)
            {
                // just advance the indexes of both sub-trees
                if (program != null)
                {
                    idx1 += (uint)program.Length - 1;
                }
                if (otherProgram != null)
                {
                    idx2 += (uint)otherProgram.Length - 1;
                }
                return;
            }

            // programs have same number of children, iterate recursively
            for (var i = 0; i < program.Input.Count; i++)
            {
                idx1++;
                idx2++;
                GetCommonRegionIndexes(program.Input[i], otherProgram.Input[i], indexes, ref idx1,
                                       ref idx2);
            }
        }
        /// <inheritdoc />
        public override ITreeProgram <double> Simplify()
        {
            // if its a constant value, just return a constant with that value
            if (this.IsConstant())
            {
                return(new Constant(this.Compute()));
            }

            // otherwise first tries to simplify children
            var input = new ITreeProgram <double> [this.Input.Count];

            for (var i = 0; i < this.Input.Count; i++)
            {
                input[i] = this.Input[i].Simplify();
            }

            // if the operands are equal, return 0
            if (input[0].Equals(input[1]))
            {
                return(Constant.Zero);
            }

            // check whether second operand is 0 and return the first
            return(input[1].EqualsConstant(0) ? input[0] : this.CreateNew(input));
        }
Beispiel #5
0
        private static ITreeProgram <TOutput> ProgramAt <TOutput>(this ITreeProgram <TOutput> program, ref uint index)
        {
            if (index == 0)
            {
                return(program);
            }
            if (program?.Input == null)
            {
                return(default(ITreeProgram <TOutput>));
            }
            if (index >= program.Length)
            {
                index -= (uint)program.Length - 1;
                return(default(ITreeProgram <TOutput>));
            }

            foreach (var child in program.Input)
            {
                index--;
                var prog = child.ProgramAt(ref index);
                if (prog != null || index == 0)
                {
                    return(prog);
                }
            }

            return(default(ITreeProgram <TOutput>));
        }
Beispiel #6
0
        /// <summary>
        ///     Mutates the given <typeparamref name="TProgram" /> by randomly replacing each sub-program by one program with the
        ///     same arity taken from the defined <see cref="PrimitiveSet{TProgram}" />.
        /// </summary>
        /// <param name="program">The program we want to mutate.</param>
        /// <returns>
        ///     A new <typeparamref name="TProgram" /> created by randomly replacing each sub-program by one program with the same
        ///     arity taken from the defined <see cref="PrimitiveSet{TProgram}" />.
        /// </returns>
        public TProgram Mutate(TProgram program)
        {
            if (program == null)
            {
                return(default(TProgram));
            }

            // mutates all children
            var numChildren = program.Input.Count;
            var newChildren = new ITreeProgram <TOutput> [numChildren];

            for (var i = 0; i < numChildren; i++)
            {
                newChildren[i] = this.Mutate((TProgram)program.Input[i]);
            }

            // checks whether to mutate this program (otherwise use same program)
            var primitive = program;

            if (this._random.NextDouble() < this.MutationProbability && this._primitives.ContainsKey(numChildren))
            {
                // mutates by creating a new random program with same arity and same children
                primitive = this._primitives[numChildren].GetRandomItem(this._random);
            }

            // creates new program with new children
            return((TProgram)primitive.CreateNew(newChildren));
        }
Beispiel #7
0
        private static ITreeProgram <TOutput> Replace <TOutput>(
            this ITreeProgram <TOutput> program, ref uint index, ITreeProgram <TOutput> newSubProgram)
        {
            if (program == null)
            {
                return(default(ITreeProgram <TOutput>));
            }
            if (index == 0)
            {
                return(newSubProgram);
            }
            if (program.Input == null)
            {
                return(program);
            }

            var newChildren = program.Input.ToArray();

            for (var i = 0; i < program.Input.Count; i++)
            {
                index--;
                newChildren[i] = Replace(program.Input[i], ref index, newSubProgram);
                if (index == 0)
                {
                    break;
                }
            }

            return(program.CreateNew(newChildren));
        }
 /// <summary>
 ///     Verifies whether the <see cref="MathProgram" /> contains a constant value, i.e., whether any one of its
 ///     descendant programs are instances have a constant value equal to <paramref name="val" />.
 /// </summary>
 /// <returns>
 ///     <c>true</c>, if program contains a constant value equal to <paramref name="val" />, <c>false</c> otherwise.
 /// </returns>
 /// <param name="program">The program to verify whether it contains a constant.</param>
 /// <param name="val">The value to test for the program.</param>
 public static bool ContainsConstant(this ITreeProgram <double> program, double val)
 {
     return(program != null &&
            (program.EqualsConstant(val) ||
             program.Input != null && program.Input.Count > 0 &&
             program.Input.Any(child => child.ContainsConstant(val))));
 }
        /// <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>
 ///     Verifies whether the <see cref="MathProgram" /> has a constant value, i.e., whether all its descendant leaf
 ///     programs are instances of <see cref="Constant" />.
 /// </summary>
 /// <returns><c>true</c>, if all leaf programs are constant, <c>false</c> otherwise.</returns>
 /// <param name="program">The program to verify whether it is a constant.</param>
 public static bool IsConstant(this ITreeProgram <double> program)
 {
     return(program != null &&
            (program is Constant ||
             program.Input != null && program.Input.Count > 0 &&
             program.Input.All(child => child.IsConstant())));
 }
        private static string GetFunctionPattern(MathProgram primitive, Variable dummy)
        {
            // creates a new function program whose children are dummies
            var children = new ITreeProgram <double> [primitive.Input?.Count ?? 0];

            for (var i = 0; i < children.Length; i++)
            {
                children[i] = dummy;
            }
            var dummyPrimitive = primitive.CreateNew(children);

            // replaces dummy labels to get programs of the expression
            var expression   = dummyPrimitive.Expression;
            var exprElements = Regex.Split(expression, $"{dummy.Label}");

            // creates a regex splitting pattern
            var pattern = new StringBuilder();

            foreach (var exprElement in exprElements)
            {
                var correctedParenthesis = exprElement.Replace("(", @"\(");
                var subPattern           = (correctedParenthesis.Length == 1 ? @"\" : string.Empty) + correctedParenthesis;
                pattern.Append($"{subPattern}{SUB_ELEM_PATTERN}");
            }

            if (exprElements.Length > 0)
            {
                pattern.Remove(pattern.Length - SUB_ELEM_PATTERN.Length, SUB_ELEM_PATTERN.Length);
            }
            return(pattern.ToString());
        }
        private TProgram Generate(PrimitiveSet <TProgram> primitives, uint depth, uint maxDepth)
        {
            // check max depth, just return a random terminal program
            if (depth == maxDepth)
            {
                return(primitives.Terminals.ToList().GetRandomItem(this._random));
            }

            // otherwise, get a random primitive
            var primitivesList = primitives.Functions.ToList();

            primitivesList.AddRange(primitives.Terminals);
            var program = primitivesList.GetRandomItem(this._random);

            // recursively generate random children for it
            var numChildren = program.Children.Count;
            var children    = new ITreeProgram <TOutput> [numChildren];

            for (var i = 0; i < numChildren; i++)
            {
                children[i] = this.Generate(primitives, depth + 1, maxDepth);
            }

            // generate a new program with the children
            return((TProgram)program.CreateNew(children));
        }
Beispiel #13
0
 /// <summary>
 ///     Creates a new <see cref="IfFunction" /> with the given sub-programs.
 /// </summary>
 /// <param name="conditionProgram">The sub-program computing the conditional value.</param>
 /// <param name="zeroProgram">The sub-program computing the value if the conditional is 0.</param>
 /// <param name="positiveProgram">The sub-program computing the value if the conditional is &gt;0</param>
 /// <param name="negativeProgram">The sub-program computing the value if the conditional is &lt;0</param>
 public IfFunction(
     ITreeProgram <double> conditionProgram, ITreeProgram <double> zeroProgram,
     ITreeProgram <double> positiveProgram, ITreeProgram <double> negativeProgram)
     : base(new[] { conditionProgram, zeroProgram, positiveProgram, negativeProgram })
 {
     this.Expression = $"({this.ConditionProgram.Expression}?{this.ZeroProgram.Expression}:" +
                       $"{this.PositiveProgram.Expression}:{this.NegativeProgram.Expression})";
 }
Beispiel #14
0
 /// <summary>
 ///     Gets the maximum breadth of the program, i.e., the number of <see cref="ITreeProgram{TOutput}" /> leaves
 ///     encountered starting from this program.
 /// </summary>
 /// <param name="program">The root program to calculate the breadth.</param>
 /// <returns>The maximum breadth of the program.</returns>
 /// <typeparam name="TOutput">The type of program output.</typeparam>
 public static uint GetMaxBreadth <TOutput>(this ITreeProgram <TOutput> program)
 {
     return(program == null
         ? 0
         : program.Input == null || program.Input.Count == 0
             ? 1
             : (uint)program.Input.Sum(child => child.GetMaxBreadth()));
 }
Beispiel #15
0
        /// <summary>
        ///     Gets all the <see cref="ITreeProgram{TOutput}" /> sub-combinations of the given program. If the program is a leaf,
        ///     there are no combinations, otherwise returns all the possible combinations between the sub-programs of the children
        ///     and also the sub-combinations of each child.
        /// </summary>
        /// <param name="program">The program we want to get the sub-combinations.</param>
        /// <returns>All the sub-combinations of the given program.</returns>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static ISet <ITreeProgram <TOutput> > GetSubCombinations <TOutput>(this ITreeProgram <TOutput> program)
        {
            //remove program itself from sub-combinations
            var subCombs = GetSubCombs(program);

            subCombs.Remove(program);
            return(subCombs);
        }
Beispiel #16
0
        /// <inheritdoc />
        public override ITreeProgram <double> Simplify()
        {
            // if its a constant value, just return a constant with that value
            if (this.IsConstant())
            {
                return(new Constant(this.Compute()));
            }

            // otherwise first tries to simplify children
            var input = new ITreeProgram <double> [this.Input.Count];

            for (var i = 0; i < this.Input.Count; i++)
            {
                input[i] = this.Input[i].Simplify();
            }

            //check whether one operand is 1 and return the other
            if (input[0].EqualsConstant(1))
            {
                return(input[1]);
            }
            if (input[1].EqualsConstant(1))
            {
                return(input[0]);
            }

            //check whether one of operands is 0 and return 0
            if (input[0].EqualsConstant(0) || input[1].EqualsConstant(0))
            {
                return(Constant.Zero);
            }

            // check whether there's a ((x*x)*x) situation, returns (x^3)
            if (input[0] is MultiplicationFunction &&
                input[0].Input[0].Equals(input[1]) && input[0].Input[1].Equals(input[1]))
            {
                return(new PowerFunction(input[1], new Constant(3)));
            }
            if (input[1] is MultiplicationFunction &&
                input[1].Input[0].Equals(input[0]) && input[1].Input[1].Equals(input[0]))
            {
                return(new PowerFunction(input[0], new Constant(3)));
            }

            // check whether there's a ((x^a)*x) situation, returns (x^(a+1))
            if (input[0] is PowerFunction && input[0].Input[1] is Constant &&
                input[0].Input[0].Equals(input[1]))
            {
                return(new PowerFunction(input[1], new Constant(input[0].Input[1].Compute() + 1)));
            }
            if (input[1] is PowerFunction && input[1].Input[1] is Constant &&
                input[1].Input[0].Equals(input[0]))
            {
                return(new PowerFunction(input[0], new Constant(input[1].Input[1].Compute() + 1)));
            }

            return(this.CreateNew(input));
        }
        /// <summary>
        ///     Converts the given <see cref="string" /> expression written in normal notation, i.e., where functions are written
        ///     in the form func(arg1 arg2 ...) or (arg1 func arg2) to a <see cref="MathProgram" />.
        /// </summary>
        /// <param name="expression">The expression we want to convert to an program.</param>
        /// <returns>A <see cref="MathProgram" /> converted from the given expression.</returns>
        public MathProgram FromNormalNotation(string expression)
        {
            if (expression == null)
            {
                return(null);
            }

            // cleans expression
            expression = expression.Replace(" ", string.Empty);

            // tests for terminals
            if (this._primitiveLabels.ContainsKey(expression))
            {
                return(this._primitiveLabels[expression]);
            }
            if (double.TryParse(expression, out var constValue))
            {
                return(new Constant(constValue));
            }

            // tests for functions
            foreach (var functionPattern in this._functionPatterns)
            {
                // checks if pattern matches
                var subExprs    = RegexSplit(expression, functionPattern.Key);
                var numChildren = functionPattern.Value.Input.Count;
                if (subExprs.Count != numChildren || subExprs.Count == 1 && string.Equals(subExprs[0], expression))
                {
                    continue;
                }

                // tries to parse sub-expressions as children
                var children = new ITreeProgram <double> [numChildren];
                var invalid  = false;
                for (var i = 0; i < numChildren; i++)
                {
                    var child = FromNormalNotation(subExprs[i]);
                    if (child == null)
                    {
                        // if a child's expression is invalid, break and try next
                        invalid = true;
                        break;
                    }

                    children[i] = child;
                }

                if (invalid)
                {
                    continue;
                }

                // creates a new program
                return((MathProgram)functionPattern.Value.CreateNew(children));
            }

            return(null);
        }
Beispiel #18
0
        /// <summary>
        ///     Gets a <see cref="IDictionary{T,T}" /> representing the program indexes in the common region between
        ///     <paramref name="program" /> and <paramref name="otherProgram" />. The dictionary represents the index
        ///     correspondence between the sub-programs of the given programs.
        /// </summary>
        /// <returns>The index correspondence between the sub-programs of the given programs.</returns>
        /// <param name="program">The first program</param>
        /// <param name="otherProgram">The other program to get the common region.</param>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static IDictionary <uint, uint> GetCommonRegionIndexes <TOutput>(
            this ITreeProgram <TOutput> program, ITreeProgram <TOutput> otherProgram)
        {
            var commonRegionIndexes = new Dictionary <uint, uint>();
            var idx1 = 0u;
            var idx2 = 0u;

            GetCommonRegionIndexes(program, otherProgram, commonRegionIndexes, ref idx1, ref idx2);
            return(commonRegionIndexes);
        }
Beispiel #19
0
        /// <summary>
        ///     Gets a dictionary containing all the <see cref="ITreeProgram{TOutput}" /> leaves of the given program and their
        ///     count. This corresponds to the leaf nodes of the expression tree of the given program.
        /// </summary>
        /// <param name="program">The program whose leaf sub-programs we want to retrieve.</param>
        /// <returns>A set containing all the <see cref="ITreeProgram{TOutput}" /> sub-programs of the given program.</returns>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static IDictionary <ITreeProgram <TOutput>, uint> GetLeaves <TOutput>(this ITreeProgram <TOutput> program)
        {
            if (program == null)
            {
                return(null);
            }
            var leaves = new Dictionary <ITreeProgram <TOutput>, uint>();

            GetLeaves(program, leaves);
            return(leaves);
        }
Beispiel #20
0
        /// <summary>
        ///     Gets a <see cref="ISet{T}" /> containing all the descendant <see cref="ITreeProgram{TOutput}" /> of the given
        ///     program.
        /// </summary>
        /// <param name="program">The program we want to get the sub-programs.</param>
        /// <returns>A set containing all the sub programs of the given program.</returns>
        /// <typeparam name="TOutput">The type of program output.</typeparam>
        public static ITreeProgram <TOutput>[] GetSubPrograms <TOutput>(this ITreeProgram <TOutput> program)
        {
            if (program == null)
            {
                return(null);
            }
            var subProgs = new ITreeProgram <TOutput> [program.Length - 1];
            var index    = 0;

            GetSubPrograms(program, ref index, program.Length - 1, subProgs);
            return(subProgs);
        }
        /// <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));
        }
Beispiel #22
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)));
        }
Beispiel #23
0
        /// <inheritdoc />
        public override ITreeProgram <double> Simplify()
        {
            // if its a constant value, just return a constant with that value
            if (this.IsConstant())
            {
                return(new Constant(this.Compute()));
            }

            // otherwise first tries to simplify children
            var input = new ITreeProgram <double> [this.Input.Count];

            for (var i = 0; i < this.Input.Count; i++)
            {
                input[i] = this.Input[i].Simplify();
            }

            //  check whether the first child is a constant and returns one of the other children accordingly
            var child1 = input[0];

            if (child1.IsConstant())
            {
                var val = child1.Compute();
                return(val.Equals(0) ? input[1] : (val > 0 ? input[2] : input[3]));
            }

            // check whether first child is a variable, check its range
            if (child1 is Variable variable)
            {
                var range = variable.Range;
                if (range.Min.Equals(0) && range.Max.Equals(0))
                {
                    return(input[1]);
                }
                if (range.Min > 0)
                {
                    return(input[2]);
                }
                if (range.Max < 0)
                {
                    return(input[3]);
                }
            }

            // check whether result children are equal, in which case replace by one of them
            if (input[1].Equals(input[2]) && input[1].Equals(input[3]))
            {
                return(input[1]);
            }

            return(this.CreateNew(input));
        }
Beispiel #24
0
        /// <summary>
        ///     Gets a program node representing the primitive of the corresponding <see cref="MathProgram" /> derived type. For
        ///     functions this corresponds to a <see cref="MathProgram" /> whose inputs are <see cref="Constant.Zero" />, for
        ///     terminals it returns the terminal itself.
        /// </summary>
        /// <returns>The default program node of the corresponding <see cref="MathProgram" /> derived type.</returns>
        public ITreeProgram <double> GetPrimitive()
        {
            if (this.Input == null || this.Input.Count == 0)
            {
                return(this);
            }
            var children = new ITreeProgram <double> [this.Input.Count];

            for (var i = 0; i < this.Input.Count; i++)
            {
                children[i] = Constant.Zero;
            }
            return(this.CreateNew(children));
        }
Beispiel #25
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)));
        }
Beispiel #26
0
        private static ITreeProgram <TOutput> GetLargestCommon(
            ref ITreeProgram <TOutput> prog1, ref ITreeProgram <TOutput> prog2,
            ISet <ITreeProgram <TOutput> > ignorePrograms = null)
        {
            // gets sub-programs and sort descendingly
            var subProgs1 = new SortedSet <ITreeProgram <TOutput> >(prog1.GetSubPrograms(),
                                                                    Comparer <ITreeProgram <TOutput> > .Create((a, b) => - (a.Length == b.Length
                                                           ? a.CompareTo(b)
                                                           : a.Length.CompareTo(b.Length))));
            var subProgs2 = new HashSet <ITreeProgram <TOutput> >(prog2.GetSubPrograms());

            return(subProgs1.FirstOrDefault(
                       subProg1 =>
                       (ignorePrograms == null || !ignorePrograms.Contains(subProg1)) && subProgs2.Contains(subProg1)));
        }
Beispiel #27
0
        private static IDictionary <ITreeProgram <TOutput>, uint> GetSubPrograms(ITreeProgram <TOutput> program)
        {
            // organizes sub-programs in dictionary-count form
            var subProgs       = program.GetSubPrograms();
            var subProgsCounts = new Dictionary <ITreeProgram <TOutput>, uint>();

            foreach (var subProg in subProgs)
            {
                if (!subProgsCounts.ContainsKey(subProg))
                {
                    subProgsCounts.Add(subProg, 0);
                }
                subProgsCounts[subProg]++;
            }
            return(subProgsCounts);
        }
        /// <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));
        }
Beispiel #29
0
        private static ISet <ITreeProgram <TOutput> > GetSubCombs <TOutput>(ITreeProgram <TOutput> program)
        {
            var combs = new HashSet <ITreeProgram <TOutput> >();

            if (program == null)
            {
                return(combs);
            }

            // checks no more children
            if (program.IsLeaf())
            {
                combs.Add(program);
                return(combs);
            }

            // gets sub-programs from all children
            var childrenSubCombs = new List <IEnumerable <ITreeProgram <TOutput> > >();

            foreach (var child in program.Input)
            {
                var childSubCombs = GetSubCombs(child);
                childrenSubCombs.Add(childSubCombs);

                // adds the sub-combinations of children to combination list
                foreach (var childSubComb in childSubCombs)
                {
                    combs.Add(childSubComb);
                }
            }

            // creates new programs where each child is replaced by some sub-combination of it
            var allChildrenCombs = childrenSubCombs.GetAllCombinations();

            foreach (var children in allChildrenCombs)
            {
                if (children.Count == program.Input.Count)
                {
                    combs.Add(program.CreateNew(children));
                }
            }

            childrenSubCombs.Clear();

            return(combs);
        }
Beispiel #30
0
        private static ISet <ITreeProgram <TOutput> > GetSubOffspring(
            ITreeProgram <TOutput> subProg1, ITreeProgram <TOutput> subProg2)
        {
            var offspring = new HashSet <ITreeProgram <TOutput> > {
                subProg1, subProg2
            };

            // check if children differ (different sub-structure) or no children -> nothing to do in this branch
            if (subProg1.Input == null || subProg2.Input == null ||
                subProg1.Input.Count != subProg2.Input.Count || subProg1.Input.Count == 0)
            {
                return(offspring);
            }

            // programs have same number of children, iterate recursively to get possible children in each sub-branch
            var numChildren = subProg1.Input.Count;
            var subChildren = new List <IEnumerable <ITreeProgram <TOutput> > >(numChildren);

            for (var i = 0; i < numChildren; i++)
            {
                subChildren.Add(GetSubOffspring(subProg1.Input[i], subProg2.Input[i]).ToList());
            }

            // gets all combinations of possible sub-branches
            var childrenCombinations = subChildren.GetAllCombinations().ToList();
            var subOffspring         = new HashSet <ITreeProgram <TOutput> >();

            // if sub-programs are the same function, we only need one of them
            if (subProg1.GetType() == subProg2.GetType())
            {
                offspring.Remove(subProg2);
            }

            // for each sub-program, creates new sub-programs for each combination
            foreach (var subProg in offspring)
            {
                foreach (var childCombination in childrenCombinations)
                {
                    subOffspring.Add(subProg.CreateNew(childCombination));
                }
            }

            return(subOffspring);
        }