public void SubtreeCrossoverDistributionsTest()
        {
            int    generations = 5;
            var    trees       = new List <ISymbolicExpressionTree>();
            var    grammar     = Grammars.CreateArithmeticAndAdfGrammar();
            var    random      = new MersenneTwister(31415);
            double msPerCrossoverEvent;

            for (int i = 0; i < POPULATION_SIZE; i++)
            {
                trees.Add(ProbabilisticTreeCreator.Create(random, grammar, 100, 10));
                for (int j = random.Next(3); j < 3; j++)
                {
                    SubroutineCreater.CreateSubroutine(random, trees[i], 100, 10, 3, 3);
                }
            }
            var children = new List <ISymbolicExpressionTree>(trees);

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int gCount = 0; gCount < generations; gCount++)
            {
                for (int i = 0; i < POPULATION_SIZE; i++)
                {
                    var par0 = (ISymbolicExpressionTree)trees.SampleRandom(random).Clone();
                    var par1 = (ISymbolicExpressionTree)trees.SampleRandom(random).Clone();
                    children[i] = SubtreeCrossover.Cross(random, par0, par1, 0.9, 100, 10);
                }
                trees = children;
            }
            stopwatch.Stop();
            foreach (var tree in trees)
            {
                Util.IsValid(tree);
            }

            msPerCrossoverEvent = stopwatch.ElapsedMilliseconds / (double)POPULATION_SIZE / (double)generations;

            Console.WriteLine("SubtreeCrossover: " + Environment.NewLine +
                              msPerCrossoverEvent + " ms per crossover event (~" + Math.Round(1000.0 / (msPerCrossoverEvent)) + "crossovers / s)" + Environment.NewLine +
                              Util.GetSizeDistributionString(trees, 105, 5) + Environment.NewLine +
                              Util.GetFunctionDistributionString(trees) + Environment.NewLine +
                              Util.GetNumberOfSubtreesDistributionString(trees) + Environment.NewLine +
                              Util.GetTerminalDistributionString(trees) + Environment.NewLine
                              );

            //mkommend: commented due to performance issues on the builder
            //Assert.IsTrue(Math.Round(1000.0 / (msPerCrossoverEvent)) > 2000); // must achieve more than 2000 x-overs/s
        }
        protected virtual ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, ItemArray <PythonStatementSemantic> semantic0, ItemArray <PythonStatementSemantic> semantic1, ICFGPythonProblemData problemData, int maxTreeLength, int maxTreeDepth, double internalCrossoverPointProbability, out ItemArray <PythonStatementSemantic> newSemantics)
        {
            if (semantic0 == null || semantic1 == null || semantic0.Length == 0 || semantic1.Length == 0)
            {
                parent0      = SubtreeCrossover.Cross(random, parent0, parent1, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth);
                newSemantics = null;
                return(parent0);
            }
            newSemantics = semantic0;

            // select a random crossover point in the first parent
            CutPoint crossoverPoint0;

            SelectCrossoverPoint(random, parent0, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth, out crossoverPoint0);

            int childLength = crossoverPoint0.Child != null?crossoverPoint0.Child.GetLength() : 0;

            // calculate the max length and depth that the inserted branch can have
            int maxInsertedBranchLength = maxTreeLength - (parent0.Length - childLength);
            int maxInsertedBranchDepth  = maxTreeDepth - parent0.Root.GetBranchLevel(crossoverPoint0.Child);

            List <ISymbolicExpressionTreeNode> allowedBranches = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.GetLength() <= maxInsertedBranchLength &&
                    n.GetDepth() <= maxInsertedBranchDepth && crossoverPoint0.IsMatchingPointType(n))
                {
                    allowedBranches.Add(n);
                }
            });
            // empty branch
            if (crossoverPoint0.IsMatchingPointType(null))
            {
                allowedBranches.Add(null);
            }

            if (allowedBranches.Count == 0)
            {
                return(parent0);
            }

            // select MaxCompares random crossover points
            // Use set to avoid having the same node multiple times
            HashSet <ISymbolicExpressionTreeNode> compBranches;

            if (allowedBranches.Count < MaxComparesParameter.Value.Value)
            {
                compBranches = new HashSet <ISymbolicExpressionTreeNode>(allowedBranches);
            }
            else
            {
                compBranches = new HashSet <ISymbolicExpressionTreeNode>();
                for (int i = 0; i < MaxComparesParameter.Value.Value; i++)
                {
                    var possibleBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
                    allowedBranches.Remove(possibleBranch);
                    compBranches.Add(possibleBranch);
                }
            }

            var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(crossoverPoint0.Parent.Grammar);

            // find first node that can be used for evaluation in parent0
            ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(crossoverPoint0.Child, statementProductionNames);

            if (statement == null)
            {
                newSemantics = SemanticSwap(crossoverPoint0, compBranches.SampleRandom(random), parent0, parent1, semantic0, semantic1);
                return(parent0);
            }

            var    statementPos0 = parent0.IterateNodesPrefix().ToList().IndexOf(statement);
            string variableSettings;

            if (problemData.VariableSettings.Count == 0)
            {
                variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(semantic0.First(x => x.TreeNodePrefixPos == statementPos0).Before, problemData.Variables.GetVariableTypes());
            }
            else
            {
                variableSettings = String.Join(Environment.NewLine, problemData.VariableSettings.Select(x => x.Value));
            }
            var variables = problemData.Variables.GetVariableNames().ToList();

            var json0 = SemanticOperatorHelper.EvaluateStatementNode(statement, PyProcess, random, problemData, variables, variableSettings, Timeout);

            ISymbolicExpressionTreeNode selectedBranch;

            if (!String.IsNullOrWhiteSpace((string)json0["exception"]))
            {
                selectedBranch = compBranches.SampleRandom(random);
            }
            else
            {
                selectedBranch = SelectBranch(statement, crossoverPoint0, compBranches, random, variables, variableSettings, json0, problemData);
            }

            // perform the actual swap
            newSemantics = SemanticSwap(crossoverPoint0, selectedBranch, parent0, parent1, semantic0, semantic1);

            return(parent0);
        }
        protected override ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, ItemArray <PythonStatementSemantic> semantic0, ItemArray <PythonStatementSemantic> semantic1, T problemData, int maxTreeLength, int maxTreeDepth, double internalCrossoverPointProbability, out ItemArray <PythonStatementSemantic> newSemantics)
        {
            if (semantic0 == null || semantic1 == null || semantic0.Length == 0 || semantic1.Length == 0)
            {
                parent0      = SubtreeCrossover.Cross(random, parent0, parent1, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth);
                newSemantics = null;
                AddStatisticsNoCrossover(NoXoNoSemantics);
                return(parent0);
            }
            newSemantics = semantic0;

            // select andom crossover points in the first parent
            var crossoverPoints0      = SelectCrossoverPointsOfMatchingType(random, parent0, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth, NumberOfCutPointsFirst);
            var primaryCrossoverPoint = crossoverPoints0.First();

            int childLength = primaryCrossoverPoint.Child != null?primaryCrossoverPoint.Child.GetLength() : 0;

            // calculate the max length and depth that the inserted branch can have
            int maxInsertedBranchLength = maxTreeLength - (parent0.Length - childLength);
            int maxInsertedBranchDepth  = maxTreeDepth - parent0.Root.GetBranchLevel(primaryCrossoverPoint.Child);

            List <ISymbolicExpressionTreeNode> allowedBranches = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.GetLength() <= maxInsertedBranchLength &&
                    n.GetDepth() <= maxInsertedBranchDepth && primaryCrossoverPoint.IsMatchingPointType(n))
                {
                    allowedBranches.Add(n);
                }
            });
            // empty branch
            if (primaryCrossoverPoint.IsMatchingPointType(null))
            {
                allowedBranches.Add(null);
            }

            // set NumberOfAllowedBranches
            NumberOfAllowedBranches = allowedBranches.Count;

            if (allowedBranches.Count == 0)
            {
                AddStatisticsNoCrossover(NoXoNoAllowedBranch);
                return(parent0);
            }

            // select NumberOfCutPointsSecond random crossover points
            // Ignore internalCrossoverPointProbability, was already used to select cutpoint and the cutpoint child already reduces possibilities
            var compBranches = allowedBranches.SampleRandomWithoutRepetition(random, NumberOfCutPointsSecond).ToList(); // convert to list so that the linq expression is only executed once, to always get the same branches

            var allowedBranchesPerCutpoint = new List <IEnumerable <ISymbolicExpressionTreeNode> >()
            {
                compBranches
            };

            allowedBranchesPerCutpoint.AddRange(crossoverPoints0.Skip(1).Select(x => FindFittingNodes(x, parent0, compBranches, maxTreeLength, maxTreeDepth)));

            // set NumberOfPossibleBranchesSelected
            NumberOfPossibleBranchesSelected = compBranches.Count;

            var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(primaryCrossoverPoint.Parent.Grammar);

            // find first node that can be used for evaluation in parent0
            ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(primaryCrossoverPoint.Child, statementProductionNames);

            if (statement == null)
            {
                newSemantics = SemanticSwap(primaryCrossoverPoint, compBranches.SampleRandom(random), parent0, parent1, semantic0, semantic1);
                AddStatisticsNoCrossover(NoXoNoStatement);
                return(parent0);
            }

            var    statementPos0 = parent0.IterateNodesPrefix().ToList().IndexOf(statement);
            string variableSettings;

            if (problemData.VariableSettings.Count == 0)
            {
                variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(semantic0.First(x => x.TreeNodePrefixPos == statementPos0).Before, problemData.Variables.GetVariableTypes());
            }
            else
            {
                variableSettings = String.Join(Environment.NewLine, problemData.VariableSettings.Select(x => x.Value));
            }
            var variables = problemData.Variables.GetVariableNames().ToList();

            // only used for analyzation, otherwise could be removed
            var json0 = SemanticOperatorHelper.EvaluateStatementNode(statement, PyProcess, random, problemData, variables, variableSettings, Timeout);

            ISymbolicExpressionTreeNode selectedBranch;
            CutPoint selectedCutPoint;

            if (statement == primaryCrossoverPoint.Child)
            {
                SelectBranchFromExecutableNodes(crossoverPoints0.ToList(), allowedBranchesPerCutpoint, random, variables, variableSettings, problemData, out selectedBranch, out selectedCutPoint);
            }
            else
            {
                //SelectBranchFromNodes1(statement, crossoverPoints0.ToList(), allowedBranchesPerCutpoint, random, variables, variableSettings, problemData, out selectedBranch, out selectedCutPoint);
                SelectBranchFromNodes2(statementProductionNames, crossoverPoints0.ToList(), allowedBranchesPerCutpoint, random, variables, variableSettings, problemData, out selectedBranch, out selectedCutPoint);
            }

            // perform the actual swap
            if (selectedBranch != null)
            {
                newSemantics = SemanticSwap(selectedCutPoint, selectedBranch, parent0, parent1, semantic0, semantic1);
                AddStatistics(semantic0, parent0, statement == primaryCrossoverPoint.Child ? selectedBranch : statement, selectedCutPoint, json0, selectedBranch, random, problemData, variables, variableSettings); // parent zero has been changed is now considered the child
            }
            else
            {
                AddStatisticsNoCrossover(NoXoNoSelectedBranch);
            }

            return(parent0);
        }
        protected override ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, ItemArray <PythonStatementSemantic> semantic0, ItemArray <PythonStatementSemantic> semantic1, T problemData, int maxTreeLength, int maxTreeDepth, double internalCrossoverPointProbability, out ItemArray <PythonStatementSemantic> newSemantics)
        {
            if (semantic0 == null || semantic1 == null || semantic0.Length == 0 || semantic1.Length == 0)
            {
                parent0      = SubtreeCrossover.Cross(random, parent0, parent1, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth);
                newSemantics = null;
                TypeSelectedForSimilarityParameter.ActualValue = new StringValue("No Semantics; Random Crossover");
                AddStatisticsNoCrossover(NoXoNoSemantics);
                return(parent0);
            }
            newSemantics = semantic0;

            var    statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(parent0.Root.Grammar);
            var    variables        = problemData.Variables.GetVariableNames().ToList();
            string variableSettings = problemData.VariableSettings.Count == 0 ? String.Empty : String.Join(Environment.NewLine, problemData.VariableSettings.Select(x => x.Value));

            int maximumSemanticTries = MaxComparesParameter.Value.Value;
            int semanticTries        = 0;

            var  saveOriginalSemantics = new List <JObject>(maximumSemanticTries);
            var  saveReplaceSemantics  = new List <JObject>(maximumSemanticTries);
            var  possibleChildren      = new List <Tuple <CutPoint, ISymbolicExpressionTreeNode> >(maximumSemanticTries);
            bool success = false;

            do
            {
                // select a random crossover point in the first parent
                CutPoint crossoverPoint0;
                SelectCrossoverPoint(random, parent0, internalCrossoverPointProbability, maxTreeLength, maxTreeDepth, out crossoverPoint0);

                int childLength = crossoverPoint0.Child != null?crossoverPoint0.Child.GetLength() : 0;

                // calculate the max length and depth that the inserted branch can have
                int maxInsertedBranchLength = Math.Max(0, maxTreeLength - (parent0.Length - childLength));
                int maxInsertedBranchDepth  = Math.Max(0, maxTreeDepth - parent0.Root.GetBranchLevel(crossoverPoint0.Parent));

                List <ISymbolicExpressionTreeNode> allowedBranches = new List <ISymbolicExpressionTreeNode>();
                parent1.Root.ForEachNodePostfix((n) => {
                    if (n.GetLength() <= maxInsertedBranchLength &&
                        n.GetDepth() <= maxInsertedBranchDepth && crossoverPoint0.IsMatchingPointType(n))
                    {
                        allowedBranches.Add(n);
                    }
                });
                // empty branch
                if (crossoverPoint0.IsMatchingPointType(null))
                {
                    allowedBranches.Add(null);
                }

                if (allowedBranches.Count != 0)
                {
                    var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);

                    ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(crossoverPoint0.Child, statementProductionNames);
                    var statementPos0 = parent0.IterateNodesPrefix().ToList().IndexOf(statement);
                    PythonStatementSemantic curSemantics = null;
                    if (String.IsNullOrEmpty(variableSettings))
                    {
                        curSemantics     = semantic0.First(x => x.TreeNodePrefixPos == statementPos0);
                        variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(curSemantics.Before, problemData.Variables.GetVariableTypes());
                    }

                    var jsonOriginal = SemanticOperatorHelper.EvaluateStatementNode(statement, PyProcess, random, problemData, variables, variableSettings, Timeout);

                    JObject jsonReplaced;
                    if (statement == crossoverPoint0.Child)
                    {
                        // selectedBranch is also executable
                        jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(selectedBranch, PyProcess, random, problemData, variables, variableSettings, Timeout);
                    }
                    else
                    {
                        crossoverPoint0.Parent.RemoveSubtree(crossoverPoint0.ChildIndex);
                        var parent = selectedBranch.Parent;                                                      // save parent
                        crossoverPoint0.Parent.InsertSubtree(crossoverPoint0.ChildIndex, selectedBranch);        // this will affect node.Parent
                        jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(statement, PyProcess, random, problemData, variables, variableSettings, Timeout);
                        crossoverPoint0.Parent.RemoveSubtree(crossoverPoint0.ChildIndex);                        // removes intermediate parent from node
                        selectedBranch.Parent = parent;                                                          // restore parent
                        crossoverPoint0.Parent.InsertSubtree(crossoverPoint0.ChildIndex, crossoverPoint0.Child); // restore cutPoint
                    }
                    var exception = jsonOriginal["exception"] != null || jsonReplaced["exception"] != null;

                    if (exception)
                    {
                        if (jsonOriginal["exception"] != null)
                        {
                            CrossoverExceptionsParameter.ActualValue.Add(new StringValue(jsonOriginal["exception"].ToString()));
                        }
                        if (jsonReplaced["exception"] != null)
                        {
                            CrossoverExceptionsParameter.ActualValue.Add(new StringValue(jsonReplaced["exception"].ToString()));
                        }
                    }

                    if (curSemantics != null && !exception)
                    {
                        jsonOriginal = PythonSemanticComparer.ReplaceNotExecutedCases(jsonOriginal, curSemantics.Before, curSemantics.ExecutedCases);
                        jsonReplaced = PythonSemanticComparer.ReplaceNotExecutedCases(jsonReplaced, curSemantics.Before, curSemantics.ExecutedCases);

                        jsonOriginal = PythonSemanticComparer.ProduceDifference(jsonOriginal, curSemantics.Before);
                        jsonReplaced = PythonSemanticComparer.ProduceDifference(jsonReplaced, curSemantics.Before);
                    }

                    if (!exception && SemanticMeasure(jsonOriginal, jsonReplaced))
                    {
                        newSemantics = SemanticSwap(crossoverPoint0, selectedBranch, parent0, parent1, semantic0, semantic1);
                        SemanticallyEquivalentCrossoverParameter.ActualValue = new IntValue(2);
                        TypeSelectedForSimilarityParameter.ActualValue       = new StringValue("First Semantic");
                        AddStatistics(semantic0, parent0, statement == crossoverPoint0.Child ? selectedBranch : statement, crossoverPoint0, jsonOriginal, selectedBranch, random, problemData, variables, variableSettings); // parent zero has been changed is now considered the child
                        success = true;
                    }
                    else
                    {
                        saveOriginalSemantics.Add(jsonOriginal);
                        saveReplaceSemantics.Add(jsonReplaced);
                        possibleChildren.Add(new Tuple <CutPoint, ISymbolicExpressionTreeNode>(crossoverPoint0, selectedBranch));
                    }
                }
                semanticTries++;

                #region try second semantic comparison
                if (!success && semanticTries >= maximumSemanticTries)
                {
                    for (int index = 0; index < saveOriginalSemantics.Count; index++)
                    {
                        var exception = saveOriginalSemantics[index]["exception"] == null && saveReplaceSemantics[index]["exception"] == null;
                        if (!exception && AdditionalSemanticMeasure(saveOriginalSemantics[index], saveReplaceSemantics[index]))
                        {
                            var crossover = possibleChildren[index];
                            crossoverPoint0 = crossover.Item1;

                            // Recreate jsonOriginal as it might have changed due to ReplaceNotExecutedCases and ProduceDifference
                            var jsonOriginal = GenerateOriginalJson(crossoverPoint0, statementProductionNames, parent0, variableSettings, semantic0, problemData, random, variables);

                            newSemantics = SemanticSwap(crossoverPoint0, crossover.Item2, parent0, parent1, semantic0, semantic1);
                            var statement = SemanticOperatorHelper.GetStatementNode(crossover.Item2, statementProductionNames);
                            SemanticallyEquivalentCrossoverParameter.ActualValue = new IntValue(2);
                            TypeSelectedForSimilarityParameter.ActualValue       = new StringValue("Second Semantic");
                            AddStatistics(semantic0, parent0, statement, crossoverPoint0, jsonOriginal, crossover.Item2, random, problemData, variables, variableSettings); // parent zero has been changed is now considered the child
                            success = true;
                            break;
                        }
                    }
                }
                #endregion
            } while (!success && semanticTries < maximumSemanticTries);

            if (!success)
            {
                // Last change. If any possible crossover was found, do a crossover with the first one
                if (saveOriginalSemantics.Any())
                {
                    var crossover       = possibleChildren.First();
                    var crossoverPoint0 = crossover.Item1;
                    // Recreate jsonOriginal as it might have changed due to ReplaceNotExecutedCases and ProduceDifference
                    var jsonOriginal = GenerateOriginalJson(crossoverPoint0, statementProductionNames, parent0, variableSettings, semantic0, problemData, random, variables);
                    newSemantics = SemanticSwap(crossoverPoint0, crossover.Item2, parent0, parent1, semantic0, semantic1);
                    var statement = SemanticOperatorHelper.GetStatementNode(crossover.Item2, statementProductionNames);
                    TypeSelectedForSimilarityParameter.ActualValue = new StringValue("Random Crossover; Reached Max Semantic Tries");
                    AddStatistics(semantic0, parent0, statement, crossoverPoint0, jsonOriginal, crossover.Item2, random, problemData, variables, variableSettings); // parent zero has been changed is now considered the child
                }
                else
                {
                    AddStatisticsNoCrossover(NoXoNoAllowedBranch);
                }
            }

            saveOriginalSemantics.Clear();
            saveReplaceSemantics.Clear();
            possibleChildren.Clear();

            NumberOfCrossoverTries = semanticTries;

            return(parent0);
        }
示例#5
0
        public void AllArchitectureAlteringOperatorsDistributionTest()
        {
            var trees    = new List <ISymbolicExpressionTree>();
            var newTrees = new List <ISymbolicExpressionTree>();
            var grammar  = Grammars.CreateArithmeticAndAdfGrammar();
            var random   = new MersenneTwister(31415);
            SymbolicExpressionTreeStringFormatter formatter = new SymbolicExpressionTreeStringFormatter();
            IntValue maxTreeSize   = new IntValue(MAX_TREE_LENGTH);
            IntValue maxTreeHeigth = new IntValue(MAX_TREE_DEPTH);
            IntValue maxDefuns     = new IntValue(3);
            IntValue maxArgs       = new IntValue(3);

            for (int i = 0; i < POPULATION_SIZE; i++)
            {
                var tree = ProbabilisticTreeCreator.Create(random, grammar, MAX_TREE_LENGTH, MAX_TREE_DEPTH);
                Util.IsValid(tree);
                trees.Add(tree);
            }
            Stopwatch stopwatch    = new Stopwatch();
            int       failedEvents = 0;

            for (int g = 0; g < N_ITERATIONS; g++)
            {
                for (int i = 0; i < POPULATION_SIZE; i++)
                {
                    if (random.NextDouble() < 0.5)
                    {
                        // manipulate
                        stopwatch.Start();
                        var  selectedTree = (ISymbolicExpressionTree)trees.SampleRandom(random).Clone();
                        var  oldTree      = (ISymbolicExpressionTree)selectedTree.Clone();
                        bool success      = false;
                        int  sw           = random.Next(6);
                        switch (sw)
                        {
                        case 0: success = ArgumentCreater.CreateNewArgument(random, selectedTree, MAX_TREE_LENGTH, MAX_TREE_DEPTH, 3, 3); break;

                        case 1: success = ArgumentDeleter.DeleteArgument(random, selectedTree, 3, 3); break;

                        case 2: success = ArgumentDuplicater.DuplicateArgument(random, selectedTree, 3, 3); break;

                        case 3: success = SubroutineCreater.CreateSubroutine(random, selectedTree, MAX_TREE_LENGTH, MAX_TREE_DEPTH, 3, 3); break;

                        case 4: success = SubroutineDuplicater.DuplicateSubroutine(random, selectedTree, 3, 3); break;

                        case 5: success = SubroutineDeleter.DeleteSubroutine(random, selectedTree, 3, 3); break;
                        }
                        stopwatch.Stop();
                        if (!success)
                        {
                            failedEvents++;
                        }
                        Util.IsValid(selectedTree);
                        newTrees.Add(selectedTree);
                    }
                    else
                    {
                        stopwatch.Start();
                        // crossover
                        SymbolicExpressionTree par0 = null;
                        SymbolicExpressionTree par1 = null;
                        do
                        {
                            par0 = (SymbolicExpressionTree)trees.SampleRandom(random).Clone();
                            par1 = (SymbolicExpressionTree)trees.SampleRandom(random).Clone();
                        } while (par0.Length > MAX_TREE_LENGTH || par1.Length > MAX_TREE_LENGTH);
                        var newTree = SubtreeCrossover.Cross(random, par0, par1, 0.9, MAX_TREE_LENGTH, MAX_TREE_DEPTH);
                        stopwatch.Stop();
                        Util.IsValid(newTree);
                        newTrees.Add(newTree);
                    }
                }
                trees = new List <ISymbolicExpressionTree>(newTrees);
                newTrees.Clear();
            }
            var msPerOperation = stopwatch.ElapsedMilliseconds / ((double)POPULATION_SIZE * (double)N_ITERATIONS);

            Console.WriteLine("AllArchitectureAlteringOperators: " + Environment.NewLine +
                              "Operations / s: ~" + Math.Round(1000.0 / (msPerOperation)) + "operations / s)" + Environment.NewLine +
                              "Failed events: " + failedEvents * 100.0 / (double)(POPULATION_SIZE * N_ITERATIONS / 2.0) + "%" + Environment.NewLine +
                              Util.GetSizeDistributionString(trees, 200, 5) + Environment.NewLine +
                              Util.GetFunctionDistributionString(trees) + Environment.NewLine +
                              Util.GetNumberOfSubtreesDistributionString(trees) + Environment.NewLine +
                              Util.GetTerminalDistributionString(trees) + Environment.NewLine
                              );

            Assert.IsTrue(failedEvents * 100.0 / (POPULATION_SIZE * N_ITERATIONS / 2.0) < 75.0); // 25% of architecture operations must succeed
            //mkommend: commented due to performance issues on the builder
            // Assert.IsTrue(Math.Round(1000.0 / (msPerOperation)) > 800); // must achieve more than 800 ops per second
        }