protected void AddStatistics(ItemArray <PythonStatementSemantic> semantic0, ISymbolicExpressionTree child, ISymbolicExpressionTreeNode statementNode, CutPoint crossoverPoint0, JObject jsonOriginal, ISymbolicExpressionTreeNode swapedBranch, IRandom random, T problemData, List <string> variables, string variableSettings)
 {
     if (SemanticallyEquivalentCrossoverParameter.ActualValue == null)
     {
         JObject jsonNow = SemanticOperatorHelper.EvaluateStatementNode(statementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);
         SemanticallyEquivalentCrossoverParameter.ActualValue = new IntValue(JToken.EqualityComparer.Equals(jsonOriginal, jsonNow) ? 1 : 2);
     }
     AddStatistics(semantic0, child);
 }
        // version 1
        // only use primary cut point
        private void SelectBranchFromNodes1(ISymbolicExpressionTreeNode statementNode, IList <CutPoint> crossoverPoints0, IList <IEnumerable <ISymbolicExpressionTreeNode> > allowedBranchesPerCutpoint, IRandom random, List <string> variables, string variableSettings, ICFGPythonProblemData problemData, out ISymbolicExpressionTreeNode selectedBranch, out CutPoint selectedCutPoint)
        {
            var jsonOutput = new Dictionary <ISymbolicExpressionTreeNode, JObject>();

            var primaryCutPoint = crossoverPoints0[0];

            primaryCutPoint.Parent.RemoveSubtree(primaryCutPoint.ChildIndex); // removes parent from child
            for (int i = 0; i < crossoverPoints0.Count; i++)
            {
                var cutPoint = crossoverPoints0[i];
                primaryCutPoint.Parent.InsertSubtree(primaryCutPoint.ChildIndex, cutPoint.Child); // this will affect cutPoint.Parent
                var jsonCur = SemanticOperatorHelper.EvaluateStatementNode(statementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);
                primaryCutPoint.Parent.RemoveSubtree(primaryCutPoint.ChildIndex);                 // removes intermediate parent from node
                cutPoint.Child.Parent = cutPoint.Parent;                                          // restore parent

                if (!String.IsNullOrWhiteSpace((string)jsonCur["exception"]))
                {
                    continue;
                }
                foreach (var possibleBranch in allowedBranchesPerCutpoint[i])
                {
                    JObject jsonPossibleBranch;
                    if (!jsonOutput.ContainsKey(possibleBranch))
                    {
                        var parent = possibleBranch.Parent;                                               // save parent
                        primaryCutPoint.Parent.InsertSubtree(primaryCutPoint.ChildIndex, possibleBranch); // this will affect node.Parent
                        jsonPossibleBranch = SemanticOperatorHelper.EvaluateStatementNode(statementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);
                        primaryCutPoint.Parent.RemoveSubtree(primaryCutPoint.ChildIndex);                 // removes intermediate parent from node
                        possibleBranch.Parent = parent;                                                   // restore parent
                        jsonOutput.Add(possibleBranch, jsonPossibleBranch);
                    }
                    else
                    {
                        jsonPossibleBranch = jsonOutput[possibleBranch];
                    }

                    if (!String.IsNullOrWhiteSpace((string)jsonPossibleBranch["exception"]))
                    {
                        continue;
                    }

                    if (!JToken.EqualityComparer.Equals(jsonCur, jsonPossibleBranch))
                    {
                        primaryCutPoint.Parent.InsertSubtree(primaryCutPoint.ChildIndex, primaryCutPoint.Child); // restore primaryCutPoint
                        selectedBranch   = possibleBranch;
                        selectedCutPoint = cutPoint;
                        return;
                    }
                }
            }

            primaryCutPoint.Parent.InsertSubtree(primaryCutPoint.ChildIndex, primaryCutPoint.Child); // restore primaryCutPoint
            // no difference was found with any comparison, select random
            selectedBranch   = allowedBranchesPerCutpoint[0].SampleRandom(random);
            selectedCutPoint = crossoverPoints0[0];
        }
        private JObject GenerateOriginalJson(CutPoint crossoverPoint0, IEnumerable <string> statementProductionNames, ISymbolicExpressionTree parent0, string variableSettings, ItemArray <PythonStatementSemantic> semantic0, ICFGPythonProblemData problemData, IRandom random, List <string> variables)
        {
            ISymbolicExpressionTreeNode statementOriginal = SemanticOperatorHelper.GetStatementNode(crossoverPoint0.Child, statementProductionNames); // statementOriginal is not always the same as statement
            var statementPos0 = parent0.IterateNodesPrefix().ToList().IndexOf(statementOriginal);

            if (String.IsNullOrEmpty(variableSettings))
            {
                var curSemantics = semantic0.First(x => x.TreeNodePrefixPos == statementPos0);
                variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(curSemantics.Before, problemData.Variables.GetVariableTypes());
            }
            return(SemanticOperatorHelper.EvaluateStatementNode(statementOriginal, PyProcess, random, problemData, variables, variableSettings, Timeout));
        }
        // version 2
        // check the statement node of every cut point in the parent
        // takes longer, but really checks for differences
        private void SelectBranchFromNodes2(IEnumerable <string> statementProductionNames, IList <CutPoint> crossoverPoints0, IList <IEnumerable <ISymbolicExpressionTreeNode> > allowedBranchesPerCutpoint, IRandom random, List <string> variables, string variableSettings, ICFGPythonProblemData problemData, out ISymbolicExpressionTreeNode selectedBranch, out CutPoint selectedCutPoint)
        {
            for (int i = 0; i < crossoverPoints0.Count; i++)
            {
                var cutPoint = crossoverPoints0[i];
                ISymbolicExpressionTreeNode curStatementNode = SemanticOperatorHelper.GetStatementNode(cutPoint.Child, statementProductionNames);
                var jsonCur = SemanticOperatorHelper.EvaluateStatementNode(curStatementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);

                if (!String.IsNullOrWhiteSpace((string)jsonCur["exception"]))
                {
                    continue;
                }
                cutPoint.Parent.RemoveSubtree(cutPoint.ChildIndex); // removes parent from node
                foreach (var possibleBranch in allowedBranchesPerCutpoint[i])
                {
                    JObject jsonPossibleBranch;
                    if (curStatementNode == cutPoint.Child)
                    {
                        // shouldn't actually happen
                        jsonPossibleBranch = SemanticOperatorHelper.EvaluateStatementNode(possibleBranch, PyProcess, random, problemData, variables, variableSettings, Timeout);
                    }
                    else
                    {
                        var parent = possibleBranch.Parent;                                 // save parent
                        cutPoint.Parent.InsertSubtree(cutPoint.ChildIndex, possibleBranch); // this will affect node.Parent
                        jsonPossibleBranch = SemanticOperatorHelper.EvaluateStatementNode(curStatementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);
                        cutPoint.Parent.RemoveSubtree(cutPoint.ChildIndex);                 // removes intermediate parent from node
                        possibleBranch.Parent = parent;                                     // restore parent
                    }

                    if (!String.IsNullOrWhiteSpace((string)jsonPossibleBranch["exception"]))
                    {
                        continue;
                    }
                    if (JToken.EqualityComparer.Equals(jsonCur, jsonPossibleBranch))
                    {
                        continue;
                    }                                                                   // equal json, therefore continue

                    cutPoint.Parent.InsertSubtree(cutPoint.ChildIndex, cutPoint.Child); // restore cutPoint
                    selectedBranch   = possibleBranch;
                    selectedCutPoint = cutPoint;
                    return;
                }
                cutPoint.Parent.InsertSubtree(cutPoint.ChildIndex, cutPoint.Child); // restore cutPoint
            }

            // no difference was found with any comparison, select randomly
            // only select form the first cut point, as the other cut points might not have allowedBranchesPerCutpoint
            selectedBranch   = allowedBranchesPerCutpoint[0].SampleRandom(random);
            selectedCutPoint = crossoverPoints0[0];
        }
        private void SelectBranchFromExecutableNodes(IList <CutPoint> crossoverPoints0, IList <IEnumerable <ISymbolicExpressionTreeNode> > allowedBranchesPerCutpoint, IRandom random, List <string> variables, string variableSettings, ICFGPythonProblemData problemData, out ISymbolicExpressionTreeNode selectedBranch, out CutPoint selectedCutPoint)
        {
            var jsonOutput = new Dictionary <ISymbolicExpressionTreeNode, JObject>();

            for (int i = 0; i < crossoverPoints0.Count; i++)
            {
                var cutPoint = crossoverPoints0[i];
                var jsonCur  = SemanticOperatorHelper.EvaluateStatementNode(cutPoint.Child, PyProcess, random, problemData, variables, variableSettings, Timeout);
                if (!String.IsNullOrWhiteSpace((string)jsonCur["exception"]))
                {
                    continue;
                }
                foreach (var possibleBranch in allowedBranchesPerCutpoint[i])
                {
                    JObject jsonPossibleBranch;
                    if (!jsonOutput.ContainsKey(possibleBranch))
                    {
                        jsonPossibleBranch = SemanticOperatorHelper.EvaluateStatementNode(possibleBranch, PyProcess, random, problemData, variables, variableSettings, Timeout);
                        jsonOutput.Add(possibleBranch, jsonPossibleBranch);
                    }
                    else
                    {
                        jsonPossibleBranch = jsonOutput[possibleBranch];
                    }

                    if (!String.IsNullOrWhiteSpace((string)jsonPossibleBranch["exception"]))
                    {
                        continue;
                    }
                    if (JToken.EqualityComparer.Equals(jsonCur, jsonPossibleBranch))
                    {
                        continue;
                    }

                    selectedBranch   = possibleBranch;
                    selectedCutPoint = cutPoint;
                    return;
                }
            }

            // no difference was found with any comparison, select random
            selectedBranch   = allowedBranchesPerCutpoint[0].SampleRandom(random);
            selectedCutPoint = crossoverPoints0[0];
        }
Exemple #6
0
        /// <summary>
        /// 1. find a mutation point
        /// 2. generate new random tree
        /// 3. calculate semantic of old and new subtree (or of the closest parent)
        /// 4. do mutation if semantically different
        /// 5. retry until a certain number of tries is reached
        ///
        /// if no mutation has happened, do random mutation
        /// </summary>
        public static void ReplaceSemanticallyDifferentBranch(IRandom random, ISymbolicExpressionTree symbolicExpressionTree, ICFGPythonProblemData problemData, ItemArray <PythonStatementSemantic> semantics, PythonProcess pythonProcess, double timeout, int maxTreeLength, int maxTreeDepth, int maximumSemanticTries)
        {
            if (semantics == null || semantics.Length == 0)
            {
                ReplaceBranchManipulation.ReplaceRandomBranch(random, symbolicExpressionTree, maxTreeLength, maxTreeDepth);
                return;
            }

            var    statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(symbolicExpressionTree.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));

            var allowedSymbols = new List <ISymbol>();
            // repeat until a fitting parent and child are found (MAX_TRIES times)
            int tries         = 0;
            int semanticTries = 0;

            do
            {
                #region find mutation point
#pragma warning disable 612, 618
                ISymbolicExpressionTreeNode parent = symbolicExpressionTree.Root.IterateNodesPrefix().Skip(1).Where(n => n.SubtreeCount > 0).SelectRandom(random);
#pragma warning restore 612, 618

                int childIndex = random.Next(parent.SubtreeCount);
                var child      = parent.GetSubtree(childIndex);
                int maxLength  = maxTreeLength - symbolicExpressionTree.Length + child.GetLength();
                int maxDepth   = maxTreeDepth - symbolicExpressionTree.Root.GetBranchLevel(child);

                allowedSymbols.Clear();
                foreach (var symbol in parent.Grammar.GetAllowedChildSymbols(parent.Symbol, childIndex))
                {
                    // check basic properties that the new symbol must have
                    if ((symbol.Name != child.Symbol.Name || symbol.MinimumArity > 0) &&
                        symbol.InitialFrequency > 0 &&
                        parent.Grammar.GetMinimumExpressionDepth(symbol) <= maxDepth &&
                        parent.Grammar.GetMinimumExpressionLength(symbol) <= maxLength)
                    {
                        allowedSymbols.Add(symbol);
                    }
                }
                #endregion

                #region check for semantic difference with a new random tree
                if (allowedSymbols.Count > 0)
                {
                    if (semanticTries <= maximumSemanticTries)
                    {
                        // do semantic mutation
                        #region calculate original json output
                        ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(child, statementProductionNames);
                        var statementPos0 = symbolicExpressionTree.IterateNodesPrefix().ToList().IndexOf(statement);
                        if (String.IsNullOrEmpty(variableSettings))
                        {
                            variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(semantics.First(x => x.TreeNodePrefixPos == statementPos0).Before, problemData.Variables.GetVariableTypes());
                        }

                        var jsonOriginal = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        #endregion

                        var seedNode = GenerateAndInsertNewSubtree(random, parent, allowedSymbols, childIndex, maxLength, maxDepth);

                        #region calculate new json output
                        JObject jsonReplaced;
                        if (child == statement)
                        {
                            // child is executable, so is the new child
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(seedNode, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }
                        else
                        {
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }

                        if (JToken.EqualityComparer.Equals(jsonOriginal, jsonReplaced))
                        {
                            // semantically equivalent. undo mutation
                            parent.RemoveSubtree(childIndex);
                            parent.InsertSubtree(childIndex, child);
                            allowedSymbols.Clear();
                        }
                        else
                        {
                            Console.WriteLine("never happens?");
                        }

                        if (problemData.VariableSettings.Count == 0)
                        {
                            // reset variableSettings
                            variableSettings = String.Empty;
                        }
                        semanticTries++;
                        #endregion
                    }
                    else
                    {
                        // do random mutation
                        GenerateAndInsertNewSubtree(random, parent, allowedSymbols, childIndex, maxLength, maxDepth);
                    }
                }
                #endregion
                tries++;
            } while (tries < MAX_TRIES && allowedSymbols.Count == 0 && semanticTries <= maximumSemanticTries);
        }
        public override void ReplaceBranch(IRandom random, ISymbolicExpressionTree symbolicExpressionTree, ICFGPythonProblemData problemData, ItemArray <PythonStatementSemantic> semantics, PythonProcess pythonProcess, double timeout, int maxTreeLength, int maxTreeDepth, int maximumSemanticTries)
        {
            if (semantics == null || semantics.Length == 0)
            {
                ReplaceBranchManipulation.ReplaceRandomBranch(random, symbolicExpressionTree, maxTreeLength, maxTreeDepth);
                SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(NoSemantics);
                MutationTypeParameter.ActualValue = new IntValue(RandomMutation);
                return;
            }

            var    statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(symbolicExpressionTree.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));

            var allowedSymbols = new List <ISymbol>();
            // repeat until a fitting parent and child are found (MAX_TRIES times)
            int tries         = 0;
            int semanticTries = 0;

            List <JObject> saveOriginalSemantics = null;
            List <JObject> saveReplaceSemantics  = null;
            List <Tuple <ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, int> > possibleChildren = null; // Item1 = parent, Item2 = seedNode, Item3 = childIndex

            if (UsesAdditionalSemanticMeasure())
            {
                saveOriginalSemantics = new List <JObject>(semanticTries);
                saveReplaceSemantics  = new List <JObject>(semanticTries);
                possibleChildren      = new List <Tuple <ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, int> >(semanticTries);
            }
            bool success = false;

            do
            {
                #region find mutation point
#pragma warning disable 612, 618
                ISymbolicExpressionTreeNode parent = symbolicExpressionTree.Root.IterateNodesPrefix().Skip(1).Where(n => n.SubtreeCount > 0).SelectRandom(random);
#pragma warning restore 612, 618

                int childIndex = random.Next(parent.SubtreeCount);
                var child      = parent.GetSubtree(childIndex);
                int maxLength  = maxTreeLength - symbolicExpressionTree.Length + child.GetLength();
                int maxDepth   = maxTreeDepth - symbolicExpressionTree.Root.GetBranchLevel(child);

                allowedSymbols.Clear();
                foreach (var symbol in parent.Grammar.GetAllowedChildSymbols(parent.Symbol, childIndex))
                {
                    // check basic properties that the new symbol must have
                    if ((symbol.Name != child.Symbol.Name || symbol.MinimumArity > 0) &&
                        symbol.InitialFrequency > 0 &&
                        parent.Grammar.GetMinimumExpressionDepth(symbol) <= maxDepth &&
                        parent.Grammar.GetMinimumExpressionLength(symbol) <= maxLength)
                    {
                        allowedSymbols.Add(symbol);
                    }
                }
                #endregion
                #region check for semantic difference with a new random tree
                if (allowedSymbols.Count > 0)
                {
                    if (semanticTries <= maximumSemanticTries)
                    {
                        // do semantic mutation
                        #region calculate original json output
                        ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(child, statementProductionNames);
                        var statementPos0 = symbolicExpressionTree.IterateNodesPrefix().ToList().IndexOf(statement);
                        PythonStatementSemantic curSemantics = null;
                        if (String.IsNullOrEmpty(variableSettings))
                        {
                            curSemantics     = semantics.First(x => x.TreeNodePrefixPos == statementPos0);
                            variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(curSemantics.Before, problemData.Variables.GetVariableTypes());
                        }

                        var jsonOriginal = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);

                        // compare jsonOriginal to semantic after! Maybe avoid additional evaluation.
                        #endregion

                        var seedNode = GenerateAndInsertNewSubtree(random, parent, allowedSymbols, childIndex, maxLength, maxDepth);

                        #region calculate new json output
                        JObject jsonReplaced;
                        if (child == statement)
                        {
                            // child is executable, so is the new child
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(seedNode, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }
                        else
                        {
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }

                        var exception = jsonOriginal["exception"] != null || jsonReplaced["exception"] != null;

                        if (exception)
                        {
                            if (jsonOriginal["exception"] != null)
                            {
                                MutationExceptionsParameter.ActualValue.Add(new StringValue(jsonOriginal["exception"].ToString()));
                            }
                            if (jsonReplaced["exception"] != null)
                            {
                                MutationExceptionsParameter.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))
                        {
                            success = true;
                            SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Different);
                            TypeSelectedForSimilarityParameter.ActualValue      = new StringValue("First Semantic");
                            MutationTypeParameter.ActualValue = new IntValue(SemanticMutation);
                        }
                        else
                        {
                            // undo mutation
                            parent.RemoveSubtree(childIndex);
                            parent.InsertSubtree(childIndex, child);
                            allowedSymbols.Clear();

                            if (!exception && UsesAdditionalSemanticMeasure())
                            {
                                saveOriginalSemantics.Add(jsonOriginal);
                                saveReplaceSemantics.Add(jsonReplaced);
                                possibleChildren.Add(new Tuple <ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, int>(parent, seedNode, childIndex));
                            }
                        }

                        if (problemData.VariableSettings.Count == 0)
                        {
                            // reset variableSettings
                            variableSettings = String.Empty;
                        }
                        semanticTries++;
                        #endregion

                        #region try second semantic comparison
                        if (!success && semanticTries >= maximumSemanticTries && UsesAdditionalSemanticMeasure())
                        {
                            for (int index = 0; index < saveOriginalSemantics.Count; index++)
                            {
                                if (AdditionalSemanticMeasure(saveOriginalSemantics[index], saveReplaceSemantics[index]))
                                {
                                    var mutation = possibleChildren[index];
                                    mutation.Item1.RemoveSubtree(mutation.Item3);
                                    mutation.Item1.InsertSubtree(mutation.Item3, mutation.Item2);
                                    success = true;
                                    SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Different);
                                    TypeSelectedForSimilarityParameter.ActualValue      = new StringValue("Second Semantic");
                                    MutationTypeParameter.ActualValue = new IntValue(SemanticMutation);
                                    break;
                                }
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        // do random mutation
                        #region calculate original json output
                        ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(child, statementProductionNames);
                        var statementPos0 = symbolicExpressionTree.IterateNodesPrefix().ToList().IndexOf(statement);
                        if (String.IsNullOrEmpty(variableSettings))
                        {
                            variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(semantics.First(x => x.TreeNodePrefixPos == statementPos0).Before, problemData.Variables.GetVariableTypes());
                        }

                        var jsonOriginal = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        #endregion

                        var     seedNode = GenerateAndInsertNewSubtree(random, parent, allowedSymbols, childIndex, maxLength, maxDepth);
                        JObject jsonReplaced;
                        if (child == statement)
                        {
                            // child is executable, so is the new child
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(seedNode, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }
                        else
                        {
                            jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                        }
                        if (JToken.EqualityComparer.Equals(jsonOriginal, jsonReplaced))
                        {
                            SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Equvivalent);
                        }
                        else
                        {
                            SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Different);
                        }
                        TypeSelectedForSimilarityParameter.ActualValue = new StringValue("Random Crossover; Reached Max Semantic Tries");
                        MutationTypeParameter.ActualValue = new IntValue(RandomMutation);
                        success = true;
                    }
                }
                #endregion
                tries++;
            } while (tries < MAX_TRIES && !success);

            NumberOfTriesParameter.ActualValue = new IntValue(semanticTries);
            if (SemanticallyEquivalentMutationParameter.ActualValue == null)
            {
                SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(NoMutation);
                TypeSelectedForSimilarityParameter.ActualValue      = new StringValue("No mutation");
                MutationTypeParameter.ActualValue = new IntValue(NoMutation);
            }
        }
        private ISymbolicExpressionTreeNode SelectBranch(ISymbolicExpressionTreeNode statementNode, CutPoint crossoverPoint0, IEnumerable <ISymbolicExpressionTreeNode> compBranches, IRandom random, List <string> variables, string variableSettings, JObject jsonParent0, ICFGPythonProblemData problemData)
        {
            List <JObject> evaluationPerNode = new List <JObject>();
            List <double>  similarity        = new List <double>();

            crossoverPoint0.Parent.RemoveSubtree(crossoverPoint0.ChildIndex); // removes parent from child
            foreach (var node in compBranches)
            {
                JObject json;
                if (statementNode == crossoverPoint0.Child)
                {
                    json = SemanticOperatorHelper.EvaluateStatementNode(node, PyProcess, random, problemData, variables, variableSettings, Timeout);
                }
                else
                {
                    var parent = node.Parent;                                               // save parent
                    crossoverPoint0.Parent.InsertSubtree(crossoverPoint0.ChildIndex, node); // this will affect node.Parent
                    json = SemanticOperatorHelper.EvaluateStatementNode(statementNode, PyProcess, random, problemData, variables, variableSettings, Timeout);
                    crossoverPoint0.Parent.RemoveSubtree(crossoverPoint0.ChildIndex);       // removes intermediate parent from node
                    node.Parent = parent;                                                   // restore parent
                }
                evaluationPerNode.Add(json);
                similarity.Add(0);
            }
            crossoverPoint0.Parent.InsertSubtree(crossoverPoint0.ChildIndex, crossoverPoint0.Child); // restore crossoverPoint0

            #region remove branches that threw an exception
            List <int> branchesCausedExceptions = new List <int>();
            for (int i = evaluationPerNode.Count - 1; i >= 0; i--)
            {
                if (evaluationPerNode[i]["exception"] != null)
                {
                    branchesCausedExceptions.Add(i);
                }
            }
            var branchesWithoutException = compBranches.ToList();
            foreach (int index in branchesCausedExceptions)
            {
                branchesWithoutException.RemoveAt(index);
                evaluationPerNode.RemoveAt(index);
                similarity.RemoveAt(index);
            }
            #endregion

            Dictionary <VariableType, List <string> > differencesPerType = new Dictionary <VariableType, List <string> >();
            foreach (var entry in problemData.Variables.GetTypesOfVariables())
            {
                List <string> differences = new List <string>();
                foreach (var variableName in entry.Value)
                {
                    if (evaluationPerNode.Any(x => !JToken.EqualityComparer.Equals(jsonParent0[variableName], x[variableName])))
                    {
                        differences.Add(variableName);
                    }
                }

                if (differences.Count > 0)
                {
                    differencesPerType.Add(entry.Key, differences);
                }
            }

            if (differencesPerType.Count == 0)
            {
                return(compBranches.SampleRandom(random));                         // no difference found, crossover with any branch
            }
            var typeDifference = differencesPerType.SampleRandom(random);
            foreach (var variableName in typeDifference.Value)
            {
                var variableSimilarity = CalculateDifference(jsonParent0[variableName], evaluationPerNode.Select(x => x[variableName]), typeDifference.Key, true);
                similarity = similarity.Zip(variableSimilarity, (x, y) => x + y).ToList();
            }
            similarity = similarity.Select(x => x / typeDifference.Value.Count).ToList(); // normalize between 0 and 1 again (actually not necessary)

            double best = Double.MaxValue;
            int    pos  = -1;
            for (int i = 0; i < similarity.Count; i++)
            {
                if (similarity[i] > 0 && similarity[i] < best)
                {
                    best = similarity[i];
                    pos  = i;
                }
            }
            return(pos >= 0 ? branchesWithoutException.ElementAt(pos) : compBranches.SampleRandom(random));
        }
        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);
        }
Exemple #12
0
        public override void ReplaceBranch(IRandom random, ISymbolicExpressionTree symbolicExpressionTree, ICFGPythonProblemData problemData, ItemArray <PythonStatementSemantic> semantics, PythonProcess pythonProcess, double timeout, int maxTreeLength, int maxTreeDepth, int maximumSemanticTries)
        {
            if (semantics == null || semantics.Length == 0)
            {
                ReplaceBranchManipulation.ReplaceRandomBranch(random, symbolicExpressionTree, maxTreeLength, maxTreeDepth);
                SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(NoSemantics);
                MutationTypeParameter.ActualValue = new IntValue(RandomMutation);
                return;
            }

            var allowedSymbols = new List <ISymbol>();
            ISymbolicExpressionTreeNode parent;
            int childIndex;
            int maxLength;
            int maxDepth;
            // repeat until a fitting parent and child are found (MAX_TRIES times)
            int tries = 0;
            ISymbolicExpressionTreeNode child;

            do
            {
#pragma warning disable 612, 618
                parent = symbolicExpressionTree.Root.IterateNodesPrefix().Skip(1).Where(n => n.SubtreeCount > 0).SelectRandom(random);
#pragma warning restore 612, 618

                childIndex = random.Next(parent.SubtreeCount);
                child      = parent.GetSubtree(childIndex);
                maxLength  = maxTreeLength - symbolicExpressionTree.Length + child.GetLength();
                maxDepth   = maxTreeDepth - symbolicExpressionTree.Root.GetBranchLevel(child);

                allowedSymbols.Clear();
                foreach (var symbol in parent.Grammar.GetAllowedChildSymbols(parent.Symbol, childIndex))
                {
                    // check basic properties that the new symbol must have
                    if ((symbol.Name != child.Symbol.Name || symbol.MinimumArity > 0) &&
                        symbol.InitialFrequency > 0 &&
                        parent.Grammar.GetMinimumExpressionDepth(symbol) <= maxDepth &&
                        parent.Grammar.GetMinimumExpressionLength(symbol) <= maxLength)
                    {
                        allowedSymbols.Add(symbol);
                    }
                }
                tries++;
            } while (tries < MAX_TRIES && allowedSymbols.Count == 0);

            NumberOfTriesParameter.ActualValue = new IntValue(tries); //normal tries. not semantic tries

            if (tries < MAX_TRIES)
            {
                var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(symbolicExpressionTree.Root.Grammar);
                var variables = problemData.Variables.GetVariableNames().ToList();

                #region calculate original json output
                ISymbolicExpressionTreeNode statement = SemanticOperatorHelper.GetStatementNode(child, statementProductionNames);
                string variableSettings = problemData.VariableSettings.Count == 0 ? String.Empty : String.Join(Environment.NewLine, problemData.VariableSettings.Select(x => x.Value));

                var statementPos0 = symbolicExpressionTree.IterateNodesPrefix().ToList().IndexOf(statement);
                if (String.IsNullOrEmpty(variableSettings))
                {
                    variableSettings = SemanticOperatorHelper.SemanticToPythonVariableSettings(semantics.First(x => x.TreeNodePrefixPos == statementPos0).Before, problemData.Variables.GetVariableTypes());
                }

                var jsonOriginal = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                #endregion

                var weights = allowedSymbols.Select(s => s.InitialFrequency).ToList();
#pragma warning disable 612, 618
                var seedSymbol = allowedSymbols.SelectRandom(weights, random);
#pragma warning restore 612, 618

                // replace the old node with the new node
                var seedNode = seedSymbol.CreateTreeNode();
                if (seedNode.HasLocalParameters)
                {
                    seedNode.ResetLocalParameters(random);
                }

                parent.RemoveSubtree(childIndex);
                parent.InsertSubtree(childIndex, seedNode);
                ProbabilisticTreeCreator.PTC2(random, seedNode, maxLength, maxDepth);

                JObject jsonReplaced;
                if (child == statement)
                {
                    // child is executable, so is the new child
                    jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(seedNode, pythonProcess, random, problemData, variables, variableSettings, timeout);
                }
                else
                {
                    jsonReplaced = SemanticOperatorHelper.EvaluateStatementNode(statement, pythonProcess, random, problemData, variables, variableSettings, timeout);
                }
                if (JToken.EqualityComparer.Equals(jsonOriginal, jsonReplaced))
                {
                    SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Equvivalent);
                }
                else
                {
                    SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(Different);
                }

                MutationTypeParameter.ActualValue = new IntValue(RandomMutation);
            }
            else
            {
                SemanticallyEquivalentMutationParameter.ActualValue = new IntValue(NoMutation);
                MutationTypeParameter.ActualValue = new IntValue(NoMutation);
            }
        }
        // ToDo: Remove workaround; use executed lines in PythonStatementSemantic
        public Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> > EvaluateAndTraceProgram(PythonProcess pythonProcess, string program, string input, string output, IEnumerable <int> indices, string header, string footer, ISymbolicExpressionTree tree, double timeout = 1)
        {
            string traceProgram = traceCodeWithVariables
                                  + program;

            traceProgram += traceCodeWithVariables == String.Empty
                    ? String.Empty
                    : traceTableReduceEntries;

            EvaluationScript es = pythonProcess.CreateEvaluationScript(traceProgram, input, output, timeout);

            es.Variables.Add("traceTable");
            es.Variables.Add("traceTableBefore");
            es.Variables.Add("executedLines");

            JObject json       = pythonProcess.SendAndEvaluateProgram(es);
            var     baseResult = pythonProcess.GetVariablesFromJson(json, indices.Count());

            if (json["traceTable"] == null)
            {
                return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, new List <PythonStatementSemantic>()));
            }

            var traceTable       = json["traceTable"].ToObject <IDictionary <int, IDictionary <string, IList> > >();
            var traceTableBefore = json["traceTableBefore"].ToObject <IDictionary <int, IDictionary <string, IList> > >();
            var executedLines    = json["executedLines"].ToObject <IDictionary <int, List <int> > >();

            List <PythonStatementSemantic> semantics = new List <PythonStatementSemantic>();
            ISymbolicExpressionTreeNode    root      = tree.Root;

            var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(root.Grammar);

            // calculate the correct line the semantic evaluation starts from
            var code    = CFGSymbolicExpressionTreeStringFormatter.StaticFormat(tree);
            int curline = es.Script.Count(c => c == '\n') - code.Count(c => c == '\n') - footer.Count(c => c == '\n') - traceTableReduceEntries.Count(c => c == '\n');

            var symbolToLineDict = FindStatementSymbolsInTree(root, statementProductionNames, ref curline);

            #region workaround: empty line problem with while, can't fix, otherwise FindStatementSymbolsInTree won't work
            string[] sciptLines       = es.Script.Split('\n');
            var      beginLineNumbers = symbolToLineDict.Values.Select(x => x[0]).Distinct().ToList();
            var      moveLines        = new Dictionary <int, int>(beginLineNumbers.Count);
            foreach (var l in beginLineNumbers)
            {
                // decrease by one, as sciptLines is an array and start from zero, where lineNumbers started counting from 1
                if (String.IsNullOrWhiteSpace(sciptLines[l - 1]) || sciptLines[l - 1].TrimStart().StartsWith("#"))
                {
                    // empty line or comment
                    var i = l + 1;
                    while (i - 1 < sciptLines.Length && (String.IsNullOrWhiteSpace(sciptLines[i - 1]) || sciptLines[i - 1].TrimStart().StartsWith("#")))
                    {
                        i++;
                    }
                    moveLines.Add(l, i);
                }
                else
                {
                    moveLines.Add(l, l);
                }
            }
            foreach (var symbolLine in symbolToLineDict)
            {
                symbolLine.Value[0] = moveLines[symbolLine.Value[0]];
            }
            #endregion
            #region fix Before line for <predefined> to have all variables initialised
            // not a great way to do it, but the python interpreter does not stop at e.g. 'while False:'
            int newMinBefore = traceTableBefore.OrderBy(x => x.Key).First(x => x.Value.ContainsKey("res0") && !x.Value["res0"].Contains(null)).Key; // first line that changes res0
            foreach (var symbolToLine in symbolToLineDict)
            {
                symbolToLine.Value.Add(symbolToLine.Value[0]); // original beginning at [2], which is needed for executed lines
                if (symbolToLine.Value[0] < newMinBefore)
                {
                    symbolToLine.Value[0] = newMinBefore;
                }
            }
            #endregion

            var prefixTreeNodes = tree.IterateNodesPrefix().ToList();

            foreach (var symbolLine in symbolToLineDict)
            {
                // Before
                Dictionary <string, IList> before = new Dictionary <string, IList>();
                foreach (var traceChange in traceTableBefore.Where(x => x.Key <= symbolLine.Value[0]).OrderByDescending(x => x.Key))
                {
                    foreach (var variableChange in traceChange.Value)
                    {
                        if (!before.ContainsKey(variableChange.Key))
                        {
                            before.Add(variableChange.Key, variableChange.Value);
                        }
                    }
                }
                // After
                Dictionary <string, IList> after = new Dictionary <string, IList>();
                foreach (var traceChange in traceTable.Where(x => x.Key >= symbolLine.Value[0] && x.Key <= symbolLine.Value[1]).OrderByDescending(x => x.Key))
                {
                    foreach (var variableChange in traceChange.Value)
                    {
                        if (!after.ContainsKey(variableChange.Key))
                        {
                            after.Add(variableChange.Key, variableChange.Value);
                        }
                    }
                }
                // clean after with before
                foreach (var key in after.Keys.ToList())
                {
                    if (PythonSemanticComparer.CompareSequence(after[key], before[key]))
                    {
                        after.Remove(key);
                    }
                }
                // add semantics
                var executedLinesWithinStatement = executedLines.Where(x => x.Key >= symbolLine.Value[2] && x.Key <= symbolLine.Value[1]);
                semantics.Add(new PythonStatementSemantic()
                {
                    TreeNodePrefixPos = prefixTreeNodes.IndexOf(symbolLine.Key),
                    ExecutedCases     = executedLinesWithinStatement.Any() ? executedLinesWithinStatement.OrderByDescending(x => x.Value.Count).First().Value : new List <int>(),
                    Before            = before,
                    After             = after,
                });
            }

            return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, semantics));
        }