/// <summary> /// generates a random valid bpm genome, using the greedy-algo. /// activities creating new objects are prefered over the rest /// </summary> /// <param name="maxDepth"></param> /// <param name="parent"></param> /// <param name="availableBpmnObjects"></param> /// <param name="currentAttributesToCover"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> public static BpmGene GenerateRandomValidBpmGenome2(int maxDepth, BpmGene parent, HashSet <BpmnObject> availableBpmnObjects = null, HashSet <BpmnProcessAttribute> currentAttributesToCover = null) { if (parent == null) { availableBpmnObjects = DataHelper.ObjectHelper.Instance().GetProcessInput(); currentAttributesToCover = DataHelper.ActivityAttributeHelper.Instance().GetAll(); } if (availableBpmnObjects == null || currentAttributesToCover == null) { throw new ArgumentNullException(nameof(availableBpmnObjects) + " or " + nameof(currentAttributesToCover)); } var currentDepth = parent.CalculateNodeDepth(); BpmGene randomGene = null; do { if (currentDepth == maxDepth) { randomGene = GenerateRandomActivity(availableBpmnObjects, currentAttributesToCover); } else { randomGene = GenerateRandomBpmGene(availableBpmnObjects, currentAttributesToCover); } } while (parent == null && randomGene == null); if (randomGene == null) { return(null); } randomGene.Parent = parent; if (randomGene is BpmnActivity) { var output = DataHelper.ActivityOutputHelper.Instance() .ProvidedOutputObjects((BpmnActivity)randomGene); availableBpmnObjects.UnionWith(output); } var numberOfChildren = randomGene.GetType().CalculateRandomNumberOfChildren(); if (randomGene is BpmnXor && numberOfChildren > 0) { // randomly xor created var xor = randomGene as BpmnXor; // divide attributes by this ID and Value var selectiveAttribute = new BpmnProcessAttribute(xor.DecisionId, xor.DecisionValue, xor.ExecutionProbability); var attributesIfCase = new HashSet <BpmnProcessAttribute>(); var attributesElseCase = new HashSet <BpmnProcessAttribute>(); // divide attributes into two buckets for ongoing process foreach (var attribute in currentAttributesToCover) { if (selectiveAttribute.DecisionId.Equals(attribute.DecisionId) && !selectiveAttribute.DecisionValue.Equals(attribute.DecisionValue)) { attributesElseCase.Add(attribute); } else { attributesIfCase.Add(attribute); } } // create new sets of bpmnobjects for both cases var availableBpmnObjectsIf = new HashSet <BpmnObject>(availableBpmnObjects); var availableBpmnObjectsElse = new HashSet <BpmnObject>(availableBpmnObjects); // add the first child var randomSubtreeIf = GenerateRandomValidBpmGenome2(maxDepth, randomGene, availableBpmnObjectsIf, attributesIfCase); xor.Children.Add(randomSubtreeIf); if (numberOfChildren > 1) { // add a second child var randomSubtreeElse = GenerateRandomValidBpmGenome2(maxDepth, randomGene, availableBpmnObjectsElse, attributesElseCase); xor.Children.Add(randomSubtreeElse); } // collect the available objects from both paths // TODO possible logic error, if both paths do not create the same output availableBpmnObjects.UnionWith(availableBpmnObjectsIf); availableBpmnObjects.UnionWith(availableBpmnObjectsElse); } if (randomGene is BpmnSeq || randomGene is BpmnAnd) { for (var i = 0; i < numberOfChildren; i++) { var availableBpmnObjectsChild = new HashSet <BpmnObject>(availableBpmnObjects); var createdSubTree = GenerateRandomValidBpmGenome2(maxDepth, randomGene, availableBpmnObjectsChild, currentAttributesToCover); if (createdSubTree == null) { Debug.WriteLine("halt"); } randomGene.Children.Add(createdSubTree); if (randomGene is BpmnSeq) { availableBpmnObjects.UnionWith(availableBpmnObjectsChild); } } } if (parent == null) { randomGene.RenumberIndicesOfBpmTree(gene => gene.Children); } return(randomGene); }
public IList <IGenome> PerformCrossover(IGenome parent1, IGenome parent2) { BpmGenome parentOne; BpmGenome parentTwo; try { parentOne = parent1 as BpmGenome; parentTwo = parent2 as BpmGenome; } catch (FormatException) { throw new FormatException($"Couldn't parse either {parent1} or {parent2} to BpmGenome!"); } catch (NullReferenceException) { throw new Exception($"Either parameter {parent1} or {parent2} were null!"); } BpmGene crossoverPointOne = null; BpmGene crossoverPointTwo = null; var max = 0; do { // Get crossover indices var randomOne = TreeHelper.RandomGenerator.Next(0, parentOne.NumberOfGenes); var randomTwo = TreeHelper.RandomGenerator.Next(0, parentTwo.NumberOfGenes); // Renumber indices accoding to Depth-First Search, because they are broken after crossing parentOne.RootGene.RenumberIndicesOfBpmTree(gen => gen.Children); parentTwo.RootGene.RenumberIndicesOfBpmTree(gen => gen.Children); // Crossover parents // Depth-first search for indices // Select subtree one crossoverPointOne = parentOne.RootGene.DepthFirstSearch(n => n.Children, element => element.Index == randomOne); // Save nodes in tmp variable // select subtre two crossoverPointTwo = parentTwo.RootGene.DepthFirstSearch(n => n.Children, element => element.Index == randomTwo); var depth1 = crossoverPointOne.CalculateNodeDepth() + crossoverPointTwo.DepthOfDeepestLeaf.Count; var depth2 = crossoverPointTwo.CalculateNodeDepth() + crossoverPointOne.DepthOfDeepestLeaf.Count; max = depth1; if (depth2 > depth1) { max = depth2; } } while (max > ModelHelper.GetBpmModel().GetMaxDepthRandomGenome()); // Set new parent node for tmp varianbles try { // remember/protect original parents var tempCrossoverPointParentOne = crossoverPointOne.Parent; var tempCrossoverPointParentTwo = crossoverPointTwo.Parent; var childIndex = TreeHelper.GetChildIndex(crossoverPointTwo.Parent, crossoverPointTwo); if (childIndex == -1) { parentTwo.RootGene = crossoverPointOne; } else { crossoverPointTwo.Parent.Children[childIndex] = crossoverPointOne; } childIndex = TreeHelper.GetChildIndex(crossoverPointOne.Parent, crossoverPointOne); if (childIndex == -1) { parentOne.RootGene = crossoverPointTwo; } else { crossoverPointOne.Parent.Children[childIndex] = crossoverPointTwo; } // top down relashions done // now handle down top relashions crossoverPointOne.Parent = tempCrossoverPointParentTwo; crossoverPointTwo.Parent = tempCrossoverPointParentOne; } catch (Exception ex) { Debug.WriteLine(ex.Message); throw new Exception($"{ex.Message}"); } // Renumber indices accoding to Depth-First Search, because they are broken after crossing parentOne.RootGene.RenumberIndicesOfBpmTree(gen => gen.Children); parentTwo.RootGene.RenumberIndicesOfBpmTree(gen => gen.Children); ProcessHelper.Validator.CheckForBpmnXorFailture(parentOne.RootGene); ProcessHelper.Validator.CheckForBpmnXorFailture(parentTwo.RootGene); // Return parents as children after exchanging subtrees at random crossover point. return(new List <IGenome> { parentOne, parentTwo }); }