Exemplo n.º 1
0
            /// <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
            });
        }