/// <summary> /// Count number of nodes in tree /// </summary> /// <param name="root">root node from tree</param> /// <param name="nodeType">node type looking for</param> /// <returns></returns> public static int CountSpecificNodes(this BpmGene root, Type nodeType) { if (root == null) { return(0); } var sum = 0; if (root.GetType() == nodeType) { sum++; } if (root is BpmnActivity) { return(sum); } if (root is BpmnAnd || root is BpmnSeq) { return(sum + root.Children.Sum(x => CountSpecificNodes(x, nodeType))); } // XOR return(sum + root.Children.Sum(x => CountSpecificNodes(x, nodeType))); }
/// <summary> /// sucht und findet Blätter mit dem speziellen Index, ansonsten return null /// </summary> /// <param name="index">Gene index</param> /// <param name="gene">starting gene</param> /// <returns></returns> public static BpmGene FindLeaf(this BpmGene gene, int index) { if (gene.Index == index) { if (gene.GetType() == typeof(BpmnActivity)) { return(gene); } else { return(null); } } // falsches blatt gefunden if (gene.Children == null || gene.Children.Count == 0) { return(null); } for (var i = gene.Children.Count - 1; i >= 0; i--) { if (gene.Children[i].Index <= index) { return(gene.Children[i].FindLeaf(index)); } } return(null); }
/// <summary> /// counts appearances of concatenating same gateways with having multiple children SEQ(SEQ(xxx)) /// </summary> /// <param name="gene"></param> /// <param name="count"></param> /// <returns></returns> public static int CheckForConcatenatingGatewaysWithSingleChild(BpmGene gene, int count = 0) { if (gene is BpmnActivity) { return(count); } if (gene.Children.Count == 1 && gene.Children[0].GetType() == gene.GetType()) { return(count + 1); } foreach (var child in gene.Children) { count += CheckForConcatenatingGatewaysWithSingleChild(child); } return(count); }
/// <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); }