private void CalculatePath(BpmnProcessAttribute bpa, BpmGene gene, List <BpmnActivity> path) { if (gene == null) { return; } if (gene is BpmnActivity) { path.Add(gene as BpmnActivity); } else if (gene is BpmnSeq || gene is BpmnAnd) { foreach (var child in gene.Children) { CalculatePath(bpa, child, path); } } else if (gene is BpmnXor) { if ((gene as BpmnXor).ToProcessAttribute().Equals(bpa)) { if (gene.Children.Count > 0) { CalculatePath(bpa, gene.Children[0], path); } } else { if (gene.Children.Count > 1) { CalculatePath(bpa, gene.Children[1], path); } } } }
private double CalculateTime(BpmnProcessAttribute bpa, BpmGene gene) { if (gene == null) { return(0); } if (gene is BpmnActivity) { return(DataHelper.ActivityHelper.Instance().GetTime((gene as BpmnActivity).Name)); } if (gene is BpmnAnd) { var max = 0.0; foreach (var child in gene.Children) { max = Math.Max(max, CalculateTime(bpa, child)); } return(max); } if (gene is BpmnSeq) { var sum = 0.0; foreach (var child in gene.Children) { sum += CalculateTime(bpa, child); } return(sum); } if ((gene as BpmnXor).ToProcessAttribute().Equals(bpa)) { if (gene.Children == null || gene.Children.Count == 0) { return(0); } else { return(CalculateTime(bpa, gene.Children[0])); } } if (gene.Children.Count > 1) { return(CalculateTime(bpa, gene.Children[1])); } return(0); }
private static void ValidateGenome(BpmGene gene, ref int failures, HashSet <BpmnObject> currentAvailableInput, HashSet <BpmnProcessAttribute> currentCoveredAttributes, int pathId, int numberOfPaths, int passedXors) { if (gene == null) { return; } if (gene is BpmnActivity) { var matchingAttributes = DataHelper.CoverHelper.Instance().CoveredAttributes(((BpmnActivity)gene).Name); var tmp = failures; failures += currentCoveredAttributes.Count(x => !matchingAttributes.Contains(x)); if (tmp != failures) { return; } var input = DataHelper.ActivityInputHelper.Instance().RequiredInputObjects((BpmnActivity)gene); failures += input.Count(x => !currentAvailableInput.Contains(x)); var output = DataHelper.ActivityOutputHelper.Instance().ProvidedOutputObjects((BpmnActivity)gene); currentAvailableInput.UnionWith(output); return; } if (gene is BpmnSeq) { foreach (var child in gene.Children) { ValidateGenome(child, ref failures, currentAvailableInput, currentCoveredAttributes, pathId, numberOfPaths, passedXors); } } if (gene is BpmnAnd) { var preAndAvailableInput = new HashSet <BpmnObject>(currentAvailableInput); var postAndAvailableInput = new HashSet <BpmnObject>(currentAvailableInput); foreach (var child in gene.Children) { var cloneCurrentAvailableInput = new HashSet <BpmnObject>(preAndAvailableInput); var cloneCurrentCoveredAttributes = new HashSet <BpmnProcessAttribute>(currentCoveredAttributes); ValidateGenome(child, ref failures, cloneCurrentAvailableInput, cloneCurrentCoveredAttributes, pathId, numberOfPaths, passedXors); postAndAvailableInput.UnionWith(cloneCurrentAvailableInput); } currentAvailableInput.UnionWith(postAndAvailableInput); } if (gene is BpmnXor) { var xor = gene as BpmnXor; // found XOR, follow decision by pathId and passedXors var decisionBase = Convert.ToString(pathId, 2).PadLeft((int)Math.Log(numberOfPaths, 2), '0'); var decision = decisionBase[passedXors] - '0'; // dirty trick var attribute = new BpmnProcessAttribute(xor.DecisionId, xor.DecisionValue, DataHelper.ActivityAttributeHelper.Instance() .GetDecisionProbability(xor.DecisionId, xor.DecisionValue)); passedXors++; var ifCase = new HashSet <BpmnProcessAttribute>(); ifCase.Add(attribute); var elseCase = new HashSet <BpmnProcessAttribute>(currentCoveredAttributes); elseCase.Remove(attribute); if (decision == 0) { ValidateGenome(gene.Children.ElementAtOrDefault(decision), ref failures, currentAvailableInput, ifCase, pathId, numberOfPaths, passedXors); } if (decision == 1) { ValidateGenome(gene.Children.ElementAtOrDefault(decision), ref failures, currentAvailableInput, elseCase, pathId, numberOfPaths, passedXors); } } }
/// <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); }
/// <summary> /// Checks, wheter all attributes are covered /// </summary> /// <param name="decision"></param> /// <param name="attributes"></param> /// <param name="gene"></param> /// <returns>false - not all attributes are covered, true - all attributes are covered</returns> private bool CheckActivityAttributeCovering(BpmnProcessAttribute decision, List <string> attributes, BpmGene gene) { if (gene == null) { return(true); } // in case of an gateway, with does not seperate attributes if (gene is BpmnAnd || gene is BpmnSeq) { foreach (var child in gene.Children) { if (CheckActivityAttributeCovering(decision, attributes, child) == false) { return(false); } } return(gene.Children.Count > 0); } // in case of an gateway, seperating attributes (like XOR) if (gene is BpmnXor) { var xor = (BpmnXor)gene; var decisionId = xor.DecisionId; var decisionValue = xor.DecisionValue; var seperate = new List <string> { decisionValue }; attributes.Remove(decisionValue); if (xor.Children == null || xor.Children.Count < 2) { return(false); } // if-case if (CheckActivityAttributeCovering(decision, seperate, xor.Children.ElementAtOrDefault(0)) == false) { return(false); } // else-case if (CheckActivityAttributeCovering(decision, attributes, xor.Children.ElementAtOrDefault(1)) == false) { return(false); } } // in case of an activity, checking if all necessary attributes are covered if (gene is BpmnActivity) { foreach (var attribute in attributes) { var activity = gene as BpmnActivity; var isCovering = DataHelper.CoverHelper.Instance() .CheckIfActivityCoversAttribute(decision.DecisionId, attribute, activity.Name); if (!isCovering) { return(false); } } } return(true); }