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); } }
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); }