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
        }
Esempio n. 2
0
        /// <summary>
        /// Takes two parent individuals P0 and P1.
        /// Randomly choose a node i from the second parent, then test all possible crossover points from the first parent to determine the best location for i to be inserted.
        /// </summary>
        public static ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, IExecutionContext context,
                                                    ISymbolicDataAnalysisSingleObjectiveEvaluator <T> evaluator, T problemData, List <int> rows, int maxDepth, int maxLength)
        {
            // randomly choose a node from the second parent
            var possibleChildren = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent1.Root)
                {
                    possibleChildren.Add(n);
                }
            });

            var selectedChild   = possibleChildren.SampleRandom(random);
            var crossoverPoints = new List <CutPoint>();
            var qualities       = new List <Tuple <CutPoint, double> >();

            parent0.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent0.Root)
                {
                    var totalDepth  = parent0.Root.GetBranchLevel(n) + selectedChild.GetDepth();
                    var totalLength = parent0.Root.GetLength() - n.GetLength() + selectedChild.GetLength();
                    if (totalDepth <= maxDepth && totalLength <= maxLength)
                    {
                        var crossoverPoint = new CutPoint(n.Parent, n);
                        if (crossoverPoint.IsMatchingPointType(selectedChild))
                        {
                            crossoverPoints.Add(crossoverPoint);
                        }
                    }
                }
            });

            if (crossoverPoints.Any())
            {
                // this loop will perform two swap operations per each crossover point
                foreach (var crossoverPoint in crossoverPoints)
                {
                    // save the old parent so we can restore it later
                    var parent = selectedChild.Parent;
                    // perform a swap and check the quality of the solution
                    Swap(crossoverPoint, selectedChild);
                    IExecutionContext childContext = new ExecutionContext(context, evaluator, context.Scope);
                    double            quality      = evaluator.Evaluate(childContext, parent0, problemData, rows);
                    qualities.Add(new Tuple <CutPoint, double>(crossoverPoint, quality));
                    // restore the correct parent
                    selectedChild.Parent = parent;
                    // swap the replaced subtree back into the tree so that the structure is preserved
                    Swap(crossoverPoint, crossoverPoint.Child);
                }

                qualities.Sort((a, b) => a.Item2.CompareTo(b.Item2)); // assuming this sorts the list in ascending order
                var crossoverPoint0 = evaluator.Maximization ? qualities.Last().Item1 : qualities.First().Item1;
                // swap the node that would create the best offspring
                // this last swap makes a total of (2 * crossoverPoints.Count() + 1) swap operations.
                Swap(crossoverPoint0, selectedChild);
            }

            return(parent0);
        }
Esempio n. 3
0
        /// <summary>
        /// Takes two parent individuals P0 and P1.
        /// Randomly choose a node i from the first parent, then test all nodes j from the second parent to determine the best child that would be obtained by swapping i for j.
        /// </summary>
        public static ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, IExecutionContext context,
                                                    ISymbolicDataAnalysisSingleObjectiveEvaluator <T> evaluator, T problemData, List <int> rows, int maxDepth, int maxLength)
        {
            var crossoverPoints0 = new List <CutPoint>();

            parent0.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent0.Root)
                {
                    crossoverPoints0.Add(new CutPoint(n.Parent, n));
                }
            });

            CutPoint crossoverPoint0 = crossoverPoints0.SampleRandom(random);
            int      level           = parent0.Root.GetBranchLevel(crossoverPoint0.Child);
            int      length          = parent0.Root.GetLength() - crossoverPoint0.Child.GetLength();

            var allowedBranches = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent1.Root)
                {
                    if (n.GetDepth() + level <= maxDepth && n.GetLength() + length <= maxLength && crossoverPoint0.IsMatchingPointType(n))
                    {
                        allowedBranches.Add(n);
                    }
                }
            });

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

            // create symbols in order to improvize an ad-hoc tree so that the child can be evaluated
            ISymbolicExpressionTreeNode selectedBranch = null;
            var nodeQualities = new List <Tuple <ISymbolicExpressionTreeNode, double> >();
            var originalChild = crossoverPoint0.Child;

            foreach (var node in allowedBranches)
            {
                var parent = node.Parent;
                Swap(crossoverPoint0, node); // the swap will set the nodes parent to crossoverPoint0.Parent
                IExecutionContext childContext = new ExecutionContext(context, evaluator, context.Scope);
                double            quality      = evaluator.Evaluate(childContext, parent0, problemData, rows);
                Swap(crossoverPoint0, originalChild); // swap the child back (so that the next swap will not affect the currently swapped node from parent1)
                nodeQualities.Add(new Tuple <ISymbolicExpressionTreeNode, double>(node, quality));
                node.Parent = parent;                 // restore correct parent
            }

            nodeQualities.Sort((a, b) => a.Item2.CompareTo(b.Item2));
            selectedBranch = evaluator.Maximization ? nodeQualities.Last().Item1 : nodeQualities.First().Item1;

            // swap the node that would create the best offspring
            Swap(crossoverPoint0, selectedBranch);
            return(parent0);
        }
Esempio n. 4
0
 public static void Shake(IRandom random, ISymbolicExpressionTree tree, double shakingFactor) {
   List<ISymbolicExpressionTreeNode> parametricNodes = new List<ISymbolicExpressionTreeNode>();
   tree.Root.ForEachNodePostfix(n => {
     if (n.HasLocalParameters) parametricNodes.Add(n);
   });
   if (parametricNodes.Count > 0) {
     var selectedPoint = parametricNodes.SampleRandom(random);
     selectedPoint.ShakeLocalParameters(random, shakingFactor);
   }
 }
Esempio n. 5
0
        public static void Shake(IRandom random, ISymbolicExpressionTree tree, double shakingFactor)
        {
            List <ISymbolicExpressionTreeNode> parametricNodes = new List <ISymbolicExpressionTreeNode>();

            tree.Root.ForEachNodePostfix(n => {
                if (n.HasLocalParameters)
                {
                    parametricNodes.Add(n);
                }
            });
            if (parametricNodes.Count > 0)
            {
                var selectedPoint = parametricNodes.SampleRandom(random);
                selectedPoint.ShakeLocalParameters(random, shakingFactor);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Genotype-to-Phenotype mapper (iterative random approach, where the next non-terminal
        /// symbol to expand is randomly determined).
        /// </summary>
        /// <param name="startNode">first node of the tree with arity 1</param>
        /// <param name="genotype">integer vector, which should be mapped to a tree</param>
        /// <param name="grammar">grammar to determine the allowed child symbols for each node</param>
        /// <param name="maxSubtreeCount">maximum allowed subtrees (= number of used genomes)</param>
        /// <param name="random">random number generator</param>
        private void MapRandomIteratively(ISymbolicExpressionTreeNode startNode,
                                          IntegerVector genotype,
                                          ISymbolicExpressionGrammar grammar,
                                          int maxSubtreeCount, IRandom random)
        {
            List <ISymbolicExpressionTreeNode> nonTerminals = new List <ISymbolicExpressionTreeNode>();

            int genotypeIndex = 0;

            nonTerminals.Add(startNode);

            while (nonTerminals.Count > 0)
            {
                if (genotypeIndex >= maxSubtreeCount)
                {
                    // if all genomes were used, only add terminal nodes to the remaining subtrees
                    ISymbolicExpressionTreeNode current = nonTerminals[0];
                    nonTerminals.RemoveAt(0);
                    current.AddSubtree(GetRandomTerminalNode(current, grammar, random));
                }
                else
                {
                    // similar to PIGEMapper, but here the current node is determined randomly ...
                    ISymbolicExpressionTreeNode current = nonTerminals.SampleRandom(random);
                    nonTerminals.Remove(current);

                    ISymbolicExpressionTreeNode newNode = GetNewChildNode(current, genotype, grammar, genotypeIndex, random);
                    int arity = SampleArity(random, newNode, grammar);

                    current.AddSubtree(newNode);
                    genotypeIndex++;
                    // new node has subtrees, so add "arity" number of copies of this node to the nonTerminals list
                    for (int i = 0; i < arity; ++i)
                    {
                        nonTerminals.Add(newNode);
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Takes two parent individuals P0 and P1.
        /// Randomly choose a node i from the first parent, then for each matching node j from the second parent, calculate the behavioral distance based on the range:
        /// d(i,j) = 0.5 * ( abs(max(i) - max(j)) + abs(min(i) - min(j)) ).
        /// Next, assign probabilities for the selection of a node j based on the inversed and normalized behavioral distance, then make a random weighted choice.
        /// </summary>
        public static ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1,
                                                    ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, T problemData, IList <int> rows, int maxDepth, int maxLength)
        {
            var crossoverPoints0 = new List <CutPoint>();

            parent0.Root.ForEachNodePostfix((n) => {
                // the if clauses prevent the root or the startnode from being selected, although the startnode can be the parent of the node being swapped.
                if (n.Parent != null && n.Parent != parent0.Root)
                {
                    crossoverPoints0.Add(new CutPoint(n.Parent, n));
                }
            });

            var crossoverPoint0 = crossoverPoints0.SampleRandom(random);
            int level           = parent0.Root.GetBranchLevel(crossoverPoint0.Child);
            int length          = parent0.Root.GetLength() - crossoverPoint0.Child.GetLength();

            var allowedBranches = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent1.Root)
                {
                    if (n.GetDepth() + level <= maxDepth && n.GetLength() + length <= maxLength && crossoverPoint0.IsMatchingPointType(n))
                    {
                        allowedBranches.Add(n);
                    }
                }
            });

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

            var dataset = problemData.Dataset;

            // create symbols in order to improvize an ad-hoc tree so that the child can be evaluated
            var    rootSymbol = new ProgramRootSymbol();
            var    startSymbol = new StartSymbol();
            var    tree0 = CreateTreeFromNode(random, crossoverPoint0.Child, rootSymbol, startSymbol); // this will change crossoverPoint0.Child.Parent
            double min0 = 0.0, max0 = 0.0;

            foreach (double v in interpreter.GetSymbolicExpressionTreeValues(tree0, dataset, rows))
            {
                if (min0 > v)
                {
                    min0 = v;
                }
                if (max0 < v)
                {
                    max0 = v;
                }
            }
            crossoverPoint0.Child.Parent = crossoverPoint0.Parent; // restore correct parent

            var weights = new List <double>();

            foreach (var node in allowedBranches)
            {
                var    parent = node.Parent;
                var    tree1 = CreateTreeFromNode(random, node, rootSymbol, startSymbol);
                double min1 = 0.0, max1 = 0.0;
                foreach (double v in interpreter.GetSymbolicExpressionTreeValues(tree1, dataset, rows))
                {
                    if (min1 > v)
                    {
                        min1 = v;
                    }
                    if (max1 < v)
                    {
                        max1 = v;
                    }
                }
                double behavioralDistance = (Math.Abs(min0 - min1) + Math.Abs(max0 - max1)) / 2; // this can be NaN of Infinity because some trees are crazy like exp(exp(exp(...))), we correct that below
                weights.Add(behavioralDistance);
                node.Parent = parent;                                                            // restore correct node parent
            }

            // remove branches with an infinite or NaN behavioral distance
            for (int i = weights.Count - 1; i >= 0; --i)
            {
                if (Double.IsNaN(weights[i]) || Double.IsInfinity(weights[i]))
                {
                    weights.RemoveAt(i);
                    allowedBranches.RemoveAt(i);
                }
            }
            // check if there are any allowed branches left
            if (allowedBranches.Count == 0)
            {
                return(parent0);
            }

            ISymbolicExpressionTreeNode selectedBranch;
            double sum = weights.Sum();

            if (sum.IsAlmost(0.0) || weights.Count == 1) // if there is only one allowed branch, or if all weights are zero
            {
                selectedBranch = allowedBranches[0];
            }
            else
            {
                for (int i = 0; i != weights.Count; ++i) // normalize and invert values
                {
                    weights[i] = 1 - weights[i] / sum;
                }

                sum = weights.Sum(); // take new sum

                // compute the probabilities (selection weights)
                for (int i = 0; i != weights.Count; ++i)
                {
                    weights[i] /= sum;
                }

#pragma warning disable 612, 618
                selectedBranch = allowedBranches.SelectRandom(weights, random);
#pragma warning restore 612, 618
            }
            Swap(crossoverPoint0, selectedBranch);
            return(parent0);
        }
        /// <summary>
        /// Takes two parent individuals P0 and P1.
        /// Randomly choose a node i from the first parent, then get a node j from the second parent that matches the semantic similarity criteria.
        /// </summary>
        public static ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
                                                    T problemData, List <int> rows, int maxDepth, int maxLength, DoubleRange range)
        {
            var crossoverPoints0 = new List <CutPoint>();

            parent0.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent0.Root)
                {
                    crossoverPoints0.Add(new CutPoint(n.Parent, n));
                }
            });

            var crossoverPoint0 = crossoverPoints0.SampleRandom(random);
            int level           = parent0.Root.GetBranchLevel(crossoverPoint0.Child);
            int length          = parent0.Root.GetLength() - crossoverPoint0.Child.GetLength();

            var allowedBranches = new List <ISymbolicExpressionTreeNode>();

            parent1.Root.ForEachNodePostfix((n) => {
                if (n.Parent != null && n.Parent != parent1.Root)
                {
                    if (n.GetDepth() + level <= maxDepth && n.GetLength() + length <= maxLength && crossoverPoint0.IsMatchingPointType(n))
                    {
                        allowedBranches.Add(n);
                    }
                }
            });

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

            var dataset = problemData.Dataset;

            // create symbols in order to improvize an ad-hoc tree so that the child can be evaluated
            var           rootSymbol       = new ProgramRootSymbol();
            var           startSymbol      = new StartSymbol();
            var           tree0            = CreateTreeFromNode(random, crossoverPoint0.Child, rootSymbol, startSymbol);
            List <double> estimatedValues0 = interpreter.GetSymbolicExpressionTreeValues(tree0, dataset, rows).ToList();

            crossoverPoint0.Child.Parent = crossoverPoint0.Parent; // restore parent
            ISymbolicExpressionTreeNode selectedBranch = null;

            // pick the first node that fulfills the semantic similarity conditions
            foreach (var node in allowedBranches)
            {
                var           parent           = node.Parent;
                var           tree1            = CreateTreeFromNode(random, node, startSymbol, rootSymbol); // this will affect node.Parent
                List <double> estimatedValues1 = interpreter.GetSymbolicExpressionTreeValues(tree1, dataset, rows).ToList();
                node.Parent = parent;                                                                       // restore parent

                OnlineCalculatorError errorState;
                double ssd = OnlineMeanAbsoluteErrorCalculator.Calculate(estimatedValues0, estimatedValues1, out errorState);

                if (range.Start <= ssd && ssd <= range.End)
                {
                    selectedBranch = node;
                    break;
                }
            }

            // perform the actual swap
            if (selectedBranch != null)
            {
                Swap(crossoverPoint0, selectedBranch);
            }
            return(parent0);
        }
Esempio n. 9
0
    /// <summary>
    /// Genotype-to-Phenotype mapper (iterative random approach, where the next non-terminal
    /// symbol to expand is randomly determined).
    /// </summary>
    /// <param name="startNode">first node of the tree with arity 1</param>
    /// <param name="genotype">integer vector, which should be mapped to a tree</param>
    /// <param name="grammar">grammar to determine the allowed child symbols for each node</param>
    /// <param name="maxSubtreeCount">maximum allowed subtrees (= number of used genomes)</param>
    /// <param name="random">random number generator</param>
    private void MapRandomIteratively(ISymbolicExpressionTreeNode startNode,
                                     IntegerVector genotype,
                                     ISymbolicExpressionGrammar grammar,
                                     int maxSubtreeCount, IRandom random) {

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

      int genotypeIndex = 0;
      nonTerminals.Add(startNode);

      while (nonTerminals.Count > 0) {
        if (genotypeIndex >= maxSubtreeCount) {
          // if all genomes were used, only add terminal nodes to the remaining subtrees
          ISymbolicExpressionTreeNode current = nonTerminals[0];
          nonTerminals.RemoveAt(0);
          current.AddSubtree(GetRandomTerminalNode(current, grammar, random));
        } else {
          // similar to PIGEMapper, but here the current node is determined randomly ...
          ISymbolicExpressionTreeNode current = nonTerminals.SampleRandom(random);
          nonTerminals.Remove(current);

          ISymbolicExpressionTreeNode newNode = GetNewChildNode(current, genotype, grammar, genotypeIndex, random);
          int arity = SampleArity(random, newNode, grammar);

          current.AddSubtree(newNode);
          genotypeIndex++;
          // new node has subtrees, so add "arity" number of copies of this node to the nonTerminals list
          for (int i = 0; i < arity; ++i) {
            nonTerminals.Add(newNode);
          }
        }
      }
    }
Esempio n. 10
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
        }