/// <summary>
        /// Adds all added Transition to the NetWithDifference
        /// </summary>
        /// <author>Jannik Arndt,Thomas Meents</author>
        public void AddAddedTransitions(PetriNet netWithDifference)
        {
            // Find all Transitions that have the DiffStatus "added"
            List<Transition> addedTransitions = ListOfChoosenProcessModels[1].Transitions.Where(transition => transition.DiffStatus == DiffState.Added).ToList();

            foreach (Transition addedTransition in addedTransitions)
            {
                netWithDifference.Places.AddRange(addedTransition.OutgoingPlaces);
                addedTransition.DiffStatus = DiffState.Added;

                // For non-starting transitions
                if (addedTransition.IncomingPlaces[0].IncomingTransitions != null && addedTransition.IncomingPlaces[0].IncomingTransitions.Count > 0)
                {
                    List<Transition> listOfFollower = new List<Transition>();
                    if (addedTransition.OutgoingPlaces[0].OutgoingTransitions.Count > 0)
                    {
                        foreach (Place t in addedTransition.OutgoingPlaces)
                            foreach (Transition newfollower in t.OutgoingTransitions)
                                if (!listOfFollower.Contains(newfollower))
                                    listOfFollower.Add(newfollower);
                    }
                    else
                    {
                        Transition follower = new Transition();
                        listOfFollower.Add(follower);
                    }

                    if (listOfFollower.Count > 0)
                    {
                        listOfFollower[0].IncomingPlaces.Add(addedTransition.OutgoingPlaces[0]);
                    }
                    else
                    {
                        Place endPlace = new Place("End");
                        addedTransition.OutgoingPlaces.Add(endPlace);
                    }
                }

                // For starting Transitions
                else
                {
                    foreach (Place t in addedTransition.OutgoingPlaces)
                    {
                        if (t.OutgoingTransitions.Count <= 0) continue;
                        addedTransition.IncomingPlaces[0].Name = "Start";
                        netWithDifference.Places.Add(addedTransition.IncomingPlaces[0]);

                        if (addedTransition.IncomingPlaces[0].OutgoingTransitions.Count > 1)
                            addedTransition.IncomingPlaces[0].OutgoingTransitions.RemoveAt(1);

                        if (addedTransition.OutgoingPlaces[0].IncomingTransitions.Count > 1)
                            addedTransition.OutgoingPlaces[0].IncomingTransitions.RemoveAt(1);

                        netWithDifference.Places.RemoveAt(0);
                    }
                }
                netWithDifference.Transitions.Add(addedTransition);
            }
        }
        public void TransitionTest()
        {
            Transition testTransition = new Transition();

            Assert.IsNotNull(testTransition.IncomingPlaces);
            Assert.IsNotNull(testTransition.OutgoingPlaces);
            Assert.IsFalse(testTransition.IsLoop);
            Assert.IsFalse(testTransition.IsANDJoin);
            Assert.IsFalse(testTransition.IsANDSplit);
        }
        public void EqualsTest()
        {
            var transition1 = new Transition("Test");
            var transition2 = new Transition("Test");
            var comparer = new TransitionComparer();

            Assert.IsTrue(comparer.Equals(transition1, transition2));
            Assert.IsTrue(comparer.Equals(transition1, transition1));
            Assert.IsFalse(comparer.Equals(transition1, null));
            Assert.IsFalse(comparer.Equals(transition2, null));
        }
        public void GetHashCodeTest()
        {
            var transition = new Transition("Test");

            var comparer = new TransitionComparer();

            var expected = "Test".GetHashCode();
            var actual = comparer.GetHashCode(transition);

            Assert.AreEqual(expected, actual);

            actual = comparer.GetHashCode(null);
            Assert.AreEqual(0, actual);
        }
        public void OutgoingANDTransitionsTest()
        {
            Place testPlace = new Place();
            Transition t1 = new Transition("t1");
            Transition t2 = new Transition("t2");
            t1.IsANDJoin = true;
            t2.IsANDSplit = true;
            testPlace.OutgoingTransitions.Add(t1);
            testPlace.OutgoingTransitions.Add(t2);

            List<Transition> result = testPlace.OutgoingANDTransitions;

            Assert.IsTrue(result.Contains(t1));
            Assert.IsTrue(result.Contains(t2));
        }
        /// <summary>
        /// This method creates a petri net with five places and four transitions.
        /// </summary>
        /// <autor>Markus Holznagel</autor>
        public static PetriNet PetriNetWithFivePlacesAndFourTransitions()
        {
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pAIn = new Place("PlaceAIn", 0);
            Place pAOut = new Place("PlaceAOut", 0);
            Place pBOut = new Place("PlaceBOut", 0);
            Place pCOut = new Place("PlaceCOut", 0);
            Place pDOut = new Place("PlaceDOut", 0);

            Transition tA = new Transition("TransitionA");
            Transition tB = new Transition("TransitionB");
            Transition tC = new Transition("TransitionC");
            Transition tD = new Transition("TransitionD");

            pAIn.AppendOutgoingTransition(tA);
            pAOut.AppendOutgoingTransition(tB);
            pBOut.AppendOutgoingTransition(tC);
            pCOut.AppendOutgoingTransition(tD);

            tA.AddOutgoingPlace(pAOut);
            tB.AddOutgoingPlace(pBOut);
            tC.AddOutgoingPlace(pCOut);
            tD.AddOutgoingPlace(pDOut);

            // Create petri net
            petriNet.Places.Add(pAIn);
            petriNet.Places.Add(pAOut);
            petriNet.Places.Add(pBOut);
            petriNet.Places.Add(pCOut);
            petriNet.Places.Add(pDOut);

            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);

            return petriNet;
        }
 /// <summary>
 /// Adds an outgoing transition to the place. This is usually called when you add a <see cref="Transition"/> to the net.
 /// </summary>
 /// <param Name="transition">The outgoing transition.</param>
 public void AppendOutgoingTransition(Transition transition)
 {
     if (!OutgoingTransitions.Contains(transition))
         OutgoingTransitions.Add(transition);
 }
        /// <summary>
        /// Draws the transition with the incoming and outgoing places.
        /// </summary>
        /// <param name="node">Node that will be drawn</param>
        /// <param name="relayed">Relayed place. It will be the incoming place of the transition</param>
        /// <param name="overwriteOutgoingPlace">optional place that will be overwrite the outgoingplace</param>
        /// <param name="overwriteIncomingPlace">optional place that will be overwrite the Incomingplace</param>
        /// <returns>Outgoing Place of the drawn Transition</returns>
        /// <author>Thomas Meents</author>
        private Place DrawLeafPetrinet(InductiveMinerTreeNode node, Place relayed, Place overwriteOutgoingPlace = null, Place overwriteIncomingPlace = null)
        {
            if (!node.Operation.Equals(OperationsEnum.isLeaf))
                throw new Exception("Only leafs can be drawn.");

            Place outgoing = new Place();
            IMPetriNet.Places.Add(outgoing);

            if (overwriteIncomingPlace != null)
                relayed = overwriteIncomingPlace;

            Transition transition = new Transition(node.Event.Name) { IsDrawn = false };
            transition.AddIncomingPlace(relayed);
            transition.AddOutgoingPlace(outgoing);
            if (overwriteOutgoingPlace != null)
            {
                transition.OutgoingPlaces.Remove(outgoing);
                transition.OutgoingPlaces.Add(overwriteOutgoingPlace);
            }
            IMPetriNet.Transitions.Add(transition);

            return outgoing;
        }
        /// <summary>
        /// Recursively moves threw the tree and generates the IMPetrinet
        /// </summary>
        /// <param name="node">actual node</param>
        /// <param name="relayedPlace">Place that the process operator get</param>
        /// <param name="relayedOutgoingPlace">optional place that will be overwrite the outgoingplace</param>
        /// <param name="relayedIncomingPlace">optional place that will be overwrite the incomingplace</param>
        /// <author>Thomas Meents, Bernd Nottbeck</author>
        private Place TraverseTreePetrinet(InductiveMinerTreeNode node, Place relayedPlace, Place relayedOutgoingPlace = null, Place relayedIncomingPlace = null)
        {
            if (node.Operation.Equals(OperationsEnum.isLeaf))
            {
                return DrawLeafPetrinet(node, relayedPlace, overwriteIncomingPlace: relayedIncomingPlace, overwriteOutgoingPlace: relayedOutgoingPlace);
            }

            if (node.Operation.Equals(OperationsEnum.isSequence))
            {
                if (node.LeftLeaf != null)
                {
                    Place temp = TraverseTreePetrinet(node.LeftLeaf, relayedPlace);
                    if (node.RightLeaf != null)
                        temp = TraverseTreePetrinet(node.RightLeaf, temp);
                    return temp;
                }
            }
            else if (node.Operation.Equals(OperationsEnum.isXOR))
            {
                if (node.LeftLeaf != null)
                {
                    Place tempXORExitPlace = TraverseTreePetrinet(node.LeftLeaf, relayedPlace);

                    if (node.RightLeaf == null)
                        return null;

                    Place newPlace = TraverseTreePetrinet(node.RightLeaf, tempXORExitPlace, relayedIncomingPlace: relayedPlace, relayedOutgoingPlace: tempXORExitPlace);

                        if (tempXORExitPlace != null)
                        return tempXORExitPlace;
                    return newPlace;
                }
            }
            else if (node.Operation.Equals(OperationsEnum.isLoop))
            {
                Place tempLoopEntrancePlace = relayedPlace;

                if (node.LeftLeaf != null)
                {
                    Place temp = TraverseTreePetrinet(node.LeftLeaf, relayedPlace);

                    Place tempLoopExitPlace = temp;

                    if (node.RightLeaf != null)
                    {
                        //prevents a Nullpointer-Exception if the first Place is a Loop.
                        if (tempLoopEntrancePlace != IMPetriNet.Places[0])
                        {
                            temp = TraverseTreePetrinet(node.RightLeaf, temp);
                            IMPetriNet.AddTransition("Loop", incomingPlace: temp, outgoingPlace: tempLoopEntrancePlace,
                                isLoop: true);
                        }
                        else
                        {
                            temp = TraverseTreePetrinet(node.RightLeaf, temp, relayedOutgoingPlace: tempLoopEntrancePlace);
                            if (tempLoopExitPlace != null)
                                temp = tempLoopExitPlace;
                        }
                    }
                    return temp;
                }
            }
            else if (node.Operation.Equals(OperationsEnum.isParallel))
            {
                Transition ANDSplit = new Transition("AND-Split");
                ANDSplit.AddIncomingPlace(relayedPlace);
                IMPetriNet.Transitions.Add(ANDSplit);

                Place NewPlaceLeft = new Place();
                Place NewPlaceRight = new Place();

                IMPetriNet.Places.Add(NewPlaceLeft);
                IMPetriNet.Places.Add(NewPlaceRight);

                ANDSplit.AddOutgoingPlace(NewPlaceLeft);
                ANDSplit.AddOutgoingPlace(NewPlaceRight);

                Transition ANDJoin = new Transition("AND-Join");
                Place AndJoinOutgoingPlace = new Place();
                ANDJoin.AddOutgoingPlace(AndJoinOutgoingPlace);
                IMPetriNet.Places.Add(AndJoinOutgoingPlace);
                IMPetriNet.Transitions.Add(ANDJoin);

                if (node.LeftLeaf != null)
                {
                    Place temp = TraverseTreePetrinet(node.LeftLeaf, relayedPlace, relayedIncomingPlace: NewPlaceLeft);
                    ANDJoin.AddIncomingPlace(temp);

                    if (node.RightLeaf != null)
                    {
                        temp = TraverseTreePetrinet(node.RightLeaf, NewPlaceRight);
                        ANDJoin.AddIncomingPlace(temp);
                    }
                    return AndJoinOutgoingPlace;
                }
            }
            else
            {
                throw new Exception("Something in the process tree is wrong.");
            }

            return relayedPlace;
        }
        /// <summary>
        /// This method creates a petri net with one loop, three places and four transitions.
        /// </summary>
        /// <autor>Thomas Meents</autor>
        public static PetriNet PetriNetWithOneLoopThreePlacesAndThreeTransitions()
        {
            PetriNet PetriNet = new PetriNet("Petri-Net Name");

            Place paIn = new Place("PlaceAIn", 0);
            Place paOut = new Place("PlaceAOut", 0);
            Place pbOut = new Place("PlaceBOut", 0);

            Transition ta = new Transition("TransitionA");
            Transition tb = new Transition("TransitionB");
            Transition tc = new Transition("");

            tb.IsLoop = true; //loop

            paIn.AppendOutgoingTransition(ta);
            paOut.AppendOutgoingTransition(tb);
            paOut.AppendIncomingTransition(tb); //loop
            pbOut.AppendOutgoingTransition(tc);
            pbOut.AppendOutgoingTransition(tb); //loop

            ta.AddOutgoingPlace(paOut);
            tb.AddOutgoingPlace(pbOut);
            tb.AddIncomingPlace(paIn); //loop

            PetriNet.Places.Add(paIn);
            PetriNet.Places.Add(paOut);
            PetriNet.Places.Add(pbOut);

            PetriNet.Transitions.Add(ta);
            PetriNet.Transitions.Add(tb);
            PetriNet.Transitions.Add(tc);

            return PetriNet;
        }
 /// <summary>
 /// Adds another PetriNet to this at the given Transition (since the other PetriNet should start with a place).
 /// Keep in mind to close all open sinks afterwards!
 /// </summary>
 /// <param name="petriNet">The other PetriNet</param>
 /// <param name="atTransition">A transition in THIS PetriNet, where the added net will be connected</param>
 /// <author>Jannik Arndt</author>
 public void MergeWithPetriNet(PetriNet petriNet, Transition atTransition)
 {
     List<Node> sources = petriNet.GetSources();
     if (sources.Count > 0)
     {
         atTransition.OutgoingPlaces.Add((sources[0] as Place));
         atTransition.OutgoingPlaces[0].AppendIncomingTransition(atTransition);
         Transitions.AddRange(petriNet.Transitions);
         Places.AddRange(petriNet.Places);
     }
 }
        /// <summary>
        /// A recursive function to call the next level of HandleNode. Also closes open XORs and ANDs right away.
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="node"></param>
        /// <param name="log"></param>
        /// <param name="petriNet"></param>
        /// <author>Jannik Arndt</author>
        public void HandleNodesAndCloseParallelisms(Transition trans, EventNode node, EventLog log, PetriNet petriNet)
        {
            var transitions = HandleNode(trans, node, log, petriNet);
            if (transitions == null)
                return;

            foreach (var transition in transitions)
                foreach (var eventNode in node.ListOfFollowers)
                    if (transition.Name == eventNode.InnerEvent.Name || transition.IsANDJoin)
                        HandleNodesAndCloseParallelisms(transition, eventNode, log, petriNet);
        }
        /// <summary>
        /// Adds a place and connects the open transitions to it. Then puts the given transition behind that whole thing.
        /// </summary>
        /// <param name="startingTransition">The starting transition</param>
        /// <param name="petriNet">The current petri net</param>
        /// <param name="endingTransition">The ending transition, if it exists already. Otherwise a new one is created.</param>
        /// <returns>The empty transition after the place that combines to XOR.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> EndXOR(List<Transition> startingTransition, PetriNet petriNet, Transition endingTransition = null)
        {
            if (endingTransition == null)
                endingTransition = petriNet.AddTransition();

            if (_openParallelismCount.Count > 0)
                _openParallelismCount.Pop();

            var newPlace = petriNet.AddPlace();
            foreach (var transition in startingTransition)
                transition.AddOutgoingPlace(newPlace);
            endingTransition.AddIncomingPlace(newPlace);
            return new List<Transition> { endingTransition };
        }
        /// <summary>
        /// Checks the parallelism of two transitions in a given petri net
        /// </summary>
        /// <param name="transition1">A Transition</param>
        /// <param name="transition2">Another Transition</param>
        /// <param name="petriNet">Petrinet</param>
        /// <param name="level"></param>
        /// <returns>Returns true if the two transitions are parallel</returns>
        /// <autor>Andrej Albrecht</autor>
        private static bool CheckTransitionIsParallel(Transition transition1, Transition transition2, PetriNet petriNet, int level = 0)
        {
            //return false if the level is to large and unreal to prevent a stackoverflow exception
            if (level > petriNet.Transitions.Count + petriNet.Places.Count) return false;

            //Same Transition is at the first call never parallel!
            if (level == 0 && transition1.Name.Equals(transition2.Name)) return false;

            //long runtime:
            //The method CheckPathToTransitionAvailable can be improved:
            if ((transition1.IncomingPlaces.Count > 1 || transition2.IncomingPlaces.Count > 1)
                && (CheckPathToTransitionAvailable(transition1, transition2) || CheckPathToTransitionAvailable(transition2, transition1)))
                //The method CheckPathToTransitionAvailable find more branches and perhaps that two transitions are not parallel
                return false;

            foreach (Place incomingPlaceOfTransition1 in transition1.IncomingPlaces)
            {
                foreach (Place incomingPlaceOfTransition2 in transition2.IncomingPlaces)
                {
                    if (incomingPlaceOfTransition1 == incomingPlaceOfTransition2)
                        return false; //Here is the only position to return a false state!

                    foreach (Transition incomingTransitionOfPlace1 in incomingPlaceOfTransition1.IncomingTransitions)
                    {
                        foreach (Transition incomingTransitionOfPlace2 in incomingPlaceOfTransition2.IncomingTransitions)
                            if (incomingTransitionOfPlace1.IsLoop ||
                                incomingTransitionOfPlace1.Name.Equals(incomingTransitionOfPlace2.Name) ||
                                CheckTransitionIsParallel(incomingTransitionOfPlace2, incomingTransitionOfPlace2, petriNet, level + 1) ||
                                CheckTransitionIsParallel(transition1, incomingTransitionOfPlace2, petriNet, level + 1))
                                return true;

                        if (CheckTransitionIsParallel(transition2, incomingTransitionOfPlace1, petriNet, level + 1))
                            return true;

                    }

                }
            }
            return false;
        }
        public void CheckCorrectFitnessBetweenEventLogAndPetrinetTest1()
        {
            //
            //EventLog
            //
            //create Case1
            Case ca1 = new Case();
            ca1.CreateEvent("A");
            ca1.CreateEvent("C");
            ca1.CreateEvent("D");
            ca1.CreateEvent("E");
            ca1.CreateEvent("H");

            //create Case2
            Case ca2 = new Case();
            ca2.CreateEvent("A");
            ca2.CreateEvent("B");
            ca2.CreateEvent("D");
            ca2.CreateEvent("E");
            ca2.CreateEvent("G");

            //create Case3
            Case ca3 = new Case();
            ca3.CreateEvent("A");
            ca3.CreateEvent("D");
            ca3.CreateEvent("C");
            ca3.CreateEvent("E");
            ca3.CreateEvent("H");

            //create Case4
            Case ca4 = new Case();
            ca4.CreateEvent("A");
            ca4.CreateEvent("B");
            ca4.CreateEvent("D");
            ca4.CreateEvent("E");
            ca4.CreateEvent("H");

            //create Case5
            Case ca5 = new Case();
            ca5.CreateEvent("A");
            ca5.CreateEvent("C");
            ca5.CreateEvent("D");
            ca5.CreateEvent("E");
            ca5.CreateEvent("G");

            //create Case6
            Case ca6 = new Case();
            ca6.CreateEvent("A");
            ca6.CreateEvent("D");
            ca6.CreateEvent("C");
            ca6.CreateEvent("E");
            ca6.CreateEvent("G");

            //create Case7
            Case ca7 = new Case();
            ca7.CreateEvent("A");
            ca7.CreateEvent("D");
            ca7.CreateEvent("B");
            ca7.CreateEvent("E");
            ca7.CreateEvent("H");

            //create Case8
            Case ca8 = new Case();
            ca8.CreateEvent("A");
            ca8.CreateEvent("C");
            ca8.CreateEvent("D");
            ca8.CreateEvent("E");
            ca8.CreateEvent("F");
            ca8.CreateEvent("D");
            ca8.CreateEvent("B");
            ca8.CreateEvent("E");
            ca8.CreateEvent("H");

            //create Case9
            Case ca9 = new Case();
            ca9.CreateEvent("A");
            ca9.CreateEvent("D");
            ca9.CreateEvent("B");
            ca9.CreateEvent("E");
            ca9.CreateEvent("G");

            //create Case10
            Case ca10 = new Case();
            ca10.CreateEvent("A");
            ca10.CreateEvent("C");
            ca10.CreateEvent("D");
            ca10.CreateEvent("E");
            ca10.CreateEvent("F");
            ca10.CreateEvent("B");
            ca10.CreateEvent("D");
            ca10.CreateEvent("E");
            ca10.CreateEvent("H");

            //create Case11
            Case ca11 = new Case();
            ca11.CreateEvent("A");
            ca11.CreateEvent("C");
            ca11.CreateEvent("D");
            ca11.CreateEvent("E");
            ca11.CreateEvent("F");
            ca11.CreateEvent("B");
            ca11.CreateEvent("D");
            ca11.CreateEvent("E");
            ca11.CreateEvent("G");

            //create Case12
            Case ca12 = new Case();
            ca12.CreateEvent("A");
            ca12.CreateEvent("C");
            ca12.CreateEvent("D");
            ca12.CreateEvent("E");
            ca12.CreateEvent("F");
            ca12.CreateEvent("D");
            ca12.CreateEvent("B");
            ca12.CreateEvent("E");
            ca12.CreateEvent("G");

            //create Case13
            Case ca13 = new Case();
            ca13.CreateEvent("A");
            ca13.CreateEvent("D");
            ca13.CreateEvent("C");
            ca13.CreateEvent("E");
            ca13.CreateEvent("F");
            ca13.CreateEvent("C");
            ca13.CreateEvent("D");
            ca13.CreateEvent("E");
            ca13.CreateEvent("H");

            //create Case14
            Case ca14 = new Case();
            ca14.CreateEvent("A");
            ca14.CreateEvent("D");
            ca14.CreateEvent("C");
            ca14.CreateEvent("E");
            ca14.CreateEvent("F");
            ca14.CreateEvent("D");
            ca14.CreateEvent("B");
            ca14.CreateEvent("E");
            ca14.CreateEvent("H");

            //create Case15
            Case ca15 = new Case();
            ca15.CreateEvent("A");
            ca15.CreateEvent("D");
            ca15.CreateEvent("C");
            ca15.CreateEvent("E");
            ca15.CreateEvent("F");
            ca15.CreateEvent("B");
            ca15.CreateEvent("D");
            ca15.CreateEvent("E");
            ca15.CreateEvent("G");

            //create Case16
            Case ca16 = new Case();
            ca16.CreateEvent("A");
            ca16.CreateEvent("C");
            ca16.CreateEvent("D");
            ca16.CreateEvent("E");
            ca16.CreateEvent("F");
            ca16.CreateEvent("B");
            ca16.CreateEvent("D");
            ca16.CreateEvent("E");
            ca16.CreateEvent("F");
            ca16.CreateEvent("D");
            ca16.CreateEvent("B");
            ca16.CreateEvent("E");
            ca16.CreateEvent("G");

            //create Case17
            Case ca17 = new Case();
            ca17.CreateEvent("A");
            ca17.CreateEvent("D");
            ca17.CreateEvent("C");
            ca17.CreateEvent("E");
            ca17.CreateEvent("F");
            ca17.CreateEvent("D");
            ca17.CreateEvent("B");
            ca17.CreateEvent("E");
            ca17.CreateEvent("G");

            //create Case18
            Case ca18 = new Case();
            ca18.CreateEvent("A");
            ca18.CreateEvent("D");
            ca18.CreateEvent("C");
            ca18.CreateEvent("E");
            ca18.CreateEvent("F");
            ca18.CreateEvent("B");
            ca18.CreateEvent("D");
            ca18.CreateEvent("E");
            ca18.CreateEvent("F");
            ca18.CreateEvent("B");
            ca18.CreateEvent("D");
            ca18.CreateEvent("E");
            ca18.CreateEvent("G");

            //create Case19
            Case ca19 = new Case();
            ca19.CreateEvent("A");
            ca19.CreateEvent("D");
            ca19.CreateEvent("C");
            ca19.CreateEvent("E");
            ca19.CreateEvent("F");
            ca19.CreateEvent("D");
            ca19.CreateEvent("B");
            ca19.CreateEvent("E");
            ca19.CreateEvent("F");
            ca19.CreateEvent("B");
            ca19.CreateEvent("D");
            ca19.CreateEvent("E");
            ca19.CreateEvent("H");

            //create Case20
            Case ca20 = new Case();
            ca20.CreateEvent("A");
            ca20.CreateEvent("D");
            ca20.CreateEvent("B");
            ca20.CreateEvent("E");
            ca20.CreateEvent("F");
            ca20.CreateEvent("B");
            ca20.CreateEvent("D");
            ca20.CreateEvent("E");
            ca20.CreateEvent("F");
            ca20.CreateEvent("D");
            ca20.CreateEvent("B");
            ca20.CreateEvent("E");
            ca20.CreateEvent("G");

            //create Case21
            Case ca21 = new Case();
            ca21.CreateEvent("A");
            ca21.CreateEvent("D");
            ca21.CreateEvent("C");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("D");
            ca21.CreateEvent("B");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("C");
            ca21.CreateEvent("D");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("D");
            ca21.CreateEvent("B");
            ca21.CreateEvent("E");
            ca21.CreateEvent("G");

            //create Event Log
            EventLog eventLog = new EventLog();
            eventLog.Cases.Add(ca1);
            eventLog.Cases.Add(ca2);
            eventLog.Cases.Add(ca3);
            eventLog.Cases.Add(ca4);
            eventLog.Cases.Add(ca5);
            eventLog.Cases.Add(ca6);
            eventLog.Cases.Add(ca7);
            eventLog.Cases.Add(ca8);
            eventLog.Cases.Add(ca9);
            eventLog.Cases.Add(ca10);
            eventLog.Cases.Add(ca11);
            eventLog.Cases.Add(ca12);
            eventLog.Cases.Add(ca13);
            eventLog.Cases.Add(ca14);
            eventLog.Cases.Add(ca15);
            eventLog.Cases.Add(ca16);
            eventLog.Cases.Add(ca17);
            eventLog.Cases.Add(ca18);
            eventLog.Cases.Add(ca19);
            eventLog.Cases.Add(ca20);
            eventLog.Cases.Add(ca21);

            //
            //PetriNet
            //
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pStart = new Place("Place Start", 0);
            Place pC1 = new Place("c1", 0);
            Place pC2 = new Place("c2", 0);
            Place pC3 = new Place("c3", 0);
            Place pC4 = new Place("c4", 0);
            Place pC5 = new Place("c5", 0);
            Place pEnd = new Place("Place End", 0);

            Transition tA = new Transition("A");
            Transition tB = new Transition("B");
            Transition tC = new Transition("C");
            Transition tD = new Transition("D");
            Transition tE = new Transition("E");
            Transition tF = new Transition("F");
            Transition tG = new Transition("G");
            Transition tH = new Transition("H");

            tG.AddOutgoingPlace(pEnd);
            tG.AddIncomingPlace(pC5);

            tH.AddOutgoingPlace(pEnd);
            tH.AddIncomingPlace(pC5);

            tE.AddIncomingPlace(pC3);
            tE.AddIncomingPlace(pC4);
            tE.AddOutgoingPlace(pC5);

            pC3.AppendIncomingTransition(tB);
            pC3.AppendIncomingTransition(tC);
            pC3.AppendOutgoingTransition(tE);

            pC4.AppendOutgoingTransition(tE);

            tB.AddIncomingPlace(pC1);
            tB.AddOutgoingPlace(pC3);

            tC.AddIncomingPlace(pC1);
            tC.AddOutgoingPlace(pC3);

            tD.AddIncomingPlace(pC2);
            tD.AddOutgoingPlace(pC4);

            pC1.AppendIncomingTransition(tA);
            pC1.AppendOutgoingTransition(tB);
            pC1.AppendOutgoingTransition(tC);

            pC2.AppendIncomingTransition(tA);
            pC2.AppendOutgoingTransition(tD);

            tF.AddIncomingPlace(pC5);
            tF.AddOutgoingPlace(pC1);
            tF.AddOutgoingPlace(pC2);

            //
            tA.AddIncomingPlace(pStart);
            tA.AddOutgoingPlace(pC1);
            tA.AddOutgoingPlace(pC2);

            pStart.AppendOutgoingTransition(tA);

            pEnd.AppendIncomingTransition(tG);
            pEnd.AppendIncomingTransition(tH);

            ////
            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);
            petriNet.Transitions.Add(tE);
            petriNet.Transitions.Add(tF);
            petriNet.Transitions.Add(tG);
            petriNet.Transitions.Add(tH);

            ////
            petriNet.Places.Add(pStart);
            petriNet.Places.Add(pC1);
            petriNet.Places.Add(pC2);
            petriNet.Places.Add(pC3);
            petriNet.Places.Add(pC4);
            petriNet.Places.Add(pC5);
            petriNet.Places.Add(pEnd);

            ComparingFootprintResultMatrix matrix = new ComparingFootprintResultMatrix(ComparingFootprintAlgorithm.CreateFootprint(eventLog), ComparingFootprintAlgorithm.CreateFootprint(petriNet));
            double fitness = ComparingFootprintAlgorithm.CalculateFitness(matrix.GetNumberOfDifferences(), matrix.GetNumberOfOpportunities());

            if (Math.Abs(fitness - 1.0) > 0.0001)
            {
                Assert.Fail("Fitness not correct! (" + fitness + ")");
            }
        }
        /// <summary>
        /// Checks if a path from a transition to another is available
        /// </summary>
        /// <param name="transition1">A Transition</param>
        /// <param name="transition2">Another Transition</param>
        /// <param name="depth">The current depth (The method set this value when it is calling itself)</param>
        /// <returns>Returns true if a path from a transition to another is available</returns>
        private static bool CheckPathToTransitionAvailable(Transition transition1, Transition transition2, int depth = 0)
        {
            if (depth > 5) return false; //beware StackOverflow
            if (transition1.Equals(transition2)) return true;

            foreach (Place pOutY in transition1.OutgoingPlaces)
                foreach (Transition pOutYtOut in pOutY.OutgoingTransitions)
                    if (transition2.Equals(pOutYtOut) || CheckPathToTransitionAvailable(pOutYtOut, transition2, depth + 1))
                        return true;
            return false;
        }
        /// <summary>
        /// This method creates a complex petri net with five places and eight transitions.
        /// </summary>
        /// <autor>Andrej Albrecht, Markus Holznagel</autor>
        public static PetriNet PetriNetWithFivePlacesAndEightTransitions()
        {
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pStart = new Place("Place Start", 0);
            Place pC1 = new Place("c1", 0);
            Place pC2 = new Place("c2", 0);
            Place pC3 = new Place("c3", 0);
            Place pC4 = new Place("c4", 0);
            Place pC5 = new Place("c5", 0);
            Place pEnd = new Place("Place End", 0);

            Transition tA = new Transition("A");
            Transition tB = new Transition("B");
            Transition tC = new Transition("C");
            Transition tD = new Transition("D");
            Transition tE = new Transition("E");
            Transition tF = new Transition("F");
            Transition tG = new Transition("G");
            Transition tH = new Transition("H");

            tG.AddOutgoingPlace(pEnd);
            tG.AddIncomingPlace(pC5);

            tH.AddOutgoingPlace(pEnd);
            tH.AddIncomingPlace(pC5);

            tE.AddIncomingPlace(pC3);
            tE.AddIncomingPlace(pC4);
            tE.AddOutgoingPlace(pC5);

            pC3.AppendIncomingTransition(tB);
            pC3.AppendIncomingTransition(tC);
            pC3.AppendOutgoingTransition(tE);

            pC4.AppendOutgoingTransition(tE);

            tB.AddIncomingPlace(pC1);
            tB.AddOutgoingPlace(pC3);

            tC.AddIncomingPlace(pC1);
            tC.AddOutgoingPlace(pC3);

            tD.AddIncomingPlace(pC2);
            tD.AddOutgoingPlace(pC4);

            pC1.AppendIncomingTransition(tA);
            pC1.AppendOutgoingTransition(tB);
            pC1.AppendOutgoingTransition(tC);

            pC2.AppendIncomingTransition(tA);
            pC2.AppendOutgoingTransition(tD);

            tF.AddIncomingPlace(pC5);
            tF.AddOutgoingPlace(pC1);
            tF.AddOutgoingPlace(pC2);

            tA.AddIncomingPlace(pStart);
            tA.AddOutgoingPlace(pC1);
            tA.AddOutgoingPlace(pC2);

            pStart.AppendOutgoingTransition(tA);

            pEnd.AppendIncomingTransition(tG);
            pEnd.AppendIncomingTransition(tH);

            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);
            petriNet.Transitions.Add(tE);
            petriNet.Transitions.Add(tF);
            petriNet.Transitions.Add(tG);
            petriNet.Transitions.Add(tH);

            petriNet.Places.Add(pStart);
            petriNet.Places.Add(pC1);
            petriNet.Places.Add(pC2);
            petriNet.Places.Add(pC3);
            petriNet.Places.Add(pC4);
            petriNet.Places.Add(pC5);
            petriNet.Places.Add(pEnd);

            return petriNet;
        }
        /// <summary>
        /// This method creates a complex petri net with six places and five transitions.
        /// </summary>
        /// <autor>Andrej Albrecht, Markus Holznagel</autor>
        public static PetriNet PetriNetWithSixPlacesAndFiveTransitions()
        {
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pStart = new Place("Place Start", 0);
            Place p1 = new Place("c1", 0);
            Place p2 = new Place("c2", 0);
            Place p3 = new Place("c3", 0);
            Place p4 = new Place("c4", 0);
            Place pEnd = new Place("Place End", 0);

            Transition tA = new Transition("A");
            Transition tB = new Transition("B");
            Transition tC = new Transition("C");
            Transition tD = new Transition("D");
            Transition tE = new Transition("E");

            pStart.AppendOutgoingTransition(tA);

            tA.AddIncomingPlace(pStart);
            tA.AddOutgoingPlace(p1);
            tA.AddOutgoingPlace(p2);

            p1.AppendIncomingTransition(tA);
            p1.AppendOutgoingTransition(tB);
            p1.AppendOutgoingTransition(tC);

            p2.AppendIncomingTransition(tA);
            p2.AppendOutgoingTransition(tC);
            p2.AppendOutgoingTransition(tD);

            tB.AddIncomingPlace(p1);
            tB.AddOutgoingPlace(p3);

            tC.AddIncomingPlace(p1);
            tC.AddIncomingPlace(p2);
            tC.AddOutgoingPlace(p3);
            tC.AddOutgoingPlace(p4);

            tD.AddIncomingPlace(p2);
            tD.AddOutgoingPlace(p4);

            p3.AppendIncomingTransition(tB);
            p3.AppendIncomingTransition(tC);
            p3.AppendOutgoingTransition(tE);

            p4.AppendIncomingTransition(tC);
            p4.AppendIncomingTransition(tD);
            p4.AppendOutgoingTransition(tE);

            tE.AddIncomingPlace(p3);
            tE.AddIncomingPlace(p4);
            tE.AddOutgoingPlace(pEnd);

            pEnd.AppendIncomingTransition(tE);

            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);
            petriNet.Transitions.Add(tE);

            petriNet.Places.Add(pStart);
            petriNet.Places.Add(p1);
            petriNet.Places.Add(p2);
            petriNet.Places.Add(p3);
            petriNet.Places.Add(p4);
            petriNet.Places.Add(pEnd);

            return petriNet;
        }
 /// <summary>
 /// Adds an incoming transition to the place. This is usually called when you add a <see cref="Transition"/> to the net.
 /// </summary>
 /// <param Name="transition">The incoming transition.</param>
 public void AppendIncomingTransition(Transition transition)
 {
     if (!IncomingTransitions.Contains(transition))
         IncomingTransitions.Add(transition);
 }
        /// <summary>
        /// Adds as many places as following events that each lead to a transition.
        /// </summary>
        /// <param name="startingTransition">Contains the starting transition</param>
        /// <param name="followers">node.followers</param>
        /// <param name="petriNet">Contains the current petri net</param>
        /// <returns>The transitions that are in an AND-relation.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAND(Transition startingTransition, List<EventNode> followers, PetriNet petriNet)
        {
            for (var index = 0; index < followers.Count; index++)
                _openParallelismCount.Push(Parallelism.And);
            var listOfFollowingTransitions = new List<Transition>();

            if (startingTransition.Name == "")
                startingTransition.Name = "AND Split";
            startingTransition.IsANDSplit = true;

            foreach (var node in followers)
            {
                var newPlace = petriNet.AddPlace();

                listOfFollowingTransitions.Add(petriNet.AddTransition(node.InnerEvent.Name, incomingPlace: newPlace));
                startingTransition.AddOutgoingPlace(newPlace);
            }
            return listOfFollowingTransitions;
        }
        /// <summary>
        /// Adds a place for each transition, then combines these places in the given transition.
        /// </summary>
        /// <param name="startingTransition">The starting transition</param>
        /// <param name="petriNet">The current petri net</param>
        /// <param name="endingTransition">The ending transition, if it exists already. Otherwise a new one is created></param>
        /// <returns>The transition where the places after the AND-related-events are connected.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> EndAND(List<Transition> startingTransition, PetriNet petriNet, Transition endingTransition = null)
        {
            if (endingTransition == null)
                endingTransition = petriNet.AddTransition();

            if (_openParallelismCount.Count > 0)
                _openParallelismCount.Pop();

            var listOfClosingPlaces = new List<Place>();
            foreach (var transition in startingTransition)
            {
                var newPlace = petriNet.AddPlace();
                transition.AddOutgoingPlace(newPlace);
                listOfClosingPlaces.Add(newPlace);
            }
            endingTransition.AddIncomingPlaces(listOfClosingPlaces);
            return new List<Transition> { endingTransition };
        }
 /// <summary>
 /// Adds an optional Transition to the net, as well as the next mandatory transition.
 /// </summary>
 /// <param name="startingTransition">The existing transition</param>
 /// <param name="optionalAction">The optional transition</param>
 /// <param name="commonAction">The mandatory transition</param>
 /// <param name="petriNet"></param>
 /// <returns></returns>
 /// <author>Jannik Arndt</author>
 public List<Transition> StartOptionalTransition(Transition startingTransition, String optionalAction, String commonAction, PetriNet petriNet)
 {
     var place1 = petriNet.AddPlace();
     var place2 = petriNet.AddPlace();
     startingTransition.AddOutgoingPlace(place1);
     petriNet.AddTransition(optionalAction, incomingPlace: place1, outgoingPlace: place2);
     var commonTransition = petriNet.AddTransition(commonAction, new List<Place> { place1, place2 });
     return new List<Transition> { commonTransition };
 }
        /// <summary>
        /// Depending on the count of followers this adds one (or more) places and their following transitions.
        /// </summary>
        /// <param name="event1"></param>
        /// <param name="node">An event node</param>
        /// <param name="log">The current event log</param>
        /// <param name="petriNet"></param>
        /// <returns>The newly added transitions. This is where you need to continue working.</returns>
        /// <exception cref="NotImplementedException">If there are more than 3 followers in a non-trivial relation.</exception>
        /// <author>Jannik Arndt</author>
        public List<Transition> HandleNode(Transition event1, EventNode node, EventLog log, PetriNet petriNet)
        {
            // Case: No followers
            if (node.ListOfFollowers.Count == 0)
                return new List<Transition>();

            // one or more more followers => count the AND-relations
            var andRelations = CountANDRelations(node, log);

            // Case: All nodes are AND-related
            if (andRelations == node.ListOfFollowers.Count)
                return StartAND(event1, node.ListOfFollowers, petriNet);

            // Case: All nodes are XOR-related
            if (andRelations == 0)
                return StartXOR(event1, node.ListOfFollowers, petriNet);

            // Case: 3 Followers
            if (node.ListOfFollowers.Count == 3)
            {
                var x = node;
                var a = node.ListOfFollowers[0];
                var b = node.ListOfFollowers[1];
                var c = node.ListOfFollowers[2];

                if (andRelations == 2) // XOR-Relations == 1
                {
                    // There are two and-relations and one xor-relation. Find the xor and order the parameters accordingly
                    if (IsXorRelation(x.InnerEvent, b.InnerEvent, c.InnerEvent, log))
                        return StartAand_BxorC(event1, a, b, c, petriNet);
                    if (IsXorRelation(x.InnerEvent, a.InnerEvent, c.InnerEvent, log))
                        return StartAand_BxorC(event1, b, a, c, petriNet);
                    if (IsXorRelation(x.InnerEvent, a.InnerEvent, b.InnerEvent, log))
                        return StartAand_BxorC(event1, c, a, b, petriNet);
                }
                else // XOR-Relations == 2 && AND-Relations == 1
                {
                    // There are two xor-relations and one and-relation. Find the and and order the parameters accordingly
                    if (IsAndRelation(x.InnerEvent, b.InnerEvent, c.InnerEvent, log))
                        return StartAxor_BandC(event1, a, b, c, petriNet);
                    if (IsAndRelation(x.InnerEvent, a.InnerEvent, c.InnerEvent, log))
                        return StartAxor_BandC(event1, b, a, c, petriNet);
                    if (IsAndRelation(x.InnerEvent, a.InnerEvent, b.InnerEvent, log))
                        return StartAxor_BandC(event1, c, a, b, petriNet);
                }
            }
            if (node.ListOfFollowers.Count > 3)
                return StartXOR(event1, node.ListOfFollowers, petriNet);

            // optional transition
            if (node.ListOfFollowers.Count == 2)
                if (log.EventFollowsEvent(node.ListOfFollowers[0].InnerEvent, node.ListOfFollowers[1].InnerEvent) > 0)
                    return StartOptionalTransition(event1, node.ListOfFollowers[0].InnerEvent.Name, node.ListOfFollowers[1].InnerEvent.Name, petriNet);
                else if (log.EventFollowsEvent(node.ListOfFollowers[1].InnerEvent, node.ListOfFollowers[0].InnerEvent) > 0)
                    return StartOptionalTransition(event1, node.ListOfFollowers[1].InnerEvent.Name, node.ListOfFollowers[0].InnerEvent.Name, petriNet);

            return null;
        }
        /// <summary>
        /// This method creates a complex petri net with fourteen places and fourteen transitions.
        /// You can choose this for testing recursive parallelisms.
        /// </summary>
        /// <autor>Markus Holznagel</autor>
        public static PetriNet PetriNetWithFourteenPlacesAndFourteenTransitions()
        {
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pStart = new Place("pStart");
            Place p1 = new Place("p1");
            Place p2 = new Place("p2");
            Place p3 = new Place("p3");
            Place p4 = new Place("p4");
            Place p5 = new Place("p5");
            Place p6 = new Place("p6");
            Place p7 = new Place("p7");
            Place p8 = new Place("p8");
            Place p9 = new Place("p9");
            Place p10 = new Place("p10");
            Place p11 = new Place("p11");
            Place p12 = new Place("p12");
            Place pEnd = new Place("pEnd");

            Transition tA = new Transition("A");
            Transition tB = new Transition("B");
            Transition tC = new Transition("C");
            Transition tD = new Transition("D");
            Transition tE = new Transition("E");
            Transition tF = new Transition("F");
            Transition tG = new Transition("G");
            Transition tH = new Transition("H");
            Transition tI = new Transition("I");
            Transition tJ = new Transition("J");
            Transition tK = new Transition("K");
            Transition tL = new Transition("L");
            Transition tM = new Transition("M");
            Transition tN = new Transition("N");

            // Transitions and Places
            pStart.AppendOutgoingTransition(tA);

            tA.AddIncomingPlace(pStart);
            tA.AddOutgoingPlace(p1);
            tA.AddOutgoingPlace(p2);

            p1.AppendIncomingTransition(tA);
            p1.AppendOutgoingTransition(tB);

            tB.AddIncomingPlace(p1);
            tB.AddOutgoingPlace(p3);
            tB.AddOutgoingPlace(p4);

            p2.AppendIncomingTransition(tA);
            p2.AppendOutgoingTransition(tC);

            tC.AddIncomingPlace(p2);
            tC.AddIncomingPlace(p5);
            tC.AddIncomingPlace(p6);

            p3.AppendIncomingTransition(tB);
            p3.AppendOutgoingTransition(tD);
            p3.AppendOutgoingTransition(tE);

            tD.AddIncomingPlace(p3);
            tD.AddOutgoingPlace(p7);

            tE.AddIncomingPlace(p3);
            tE.AddOutgoingPlace(p7);

            p4.AppendIncomingTransition(tB);
            p4.AppendOutgoingTransition(tF);
            p4.AppendOutgoingTransition(tG);

            tF.AddIncomingPlace(p4);
            tF.AddOutgoingPlace(p8);

            tG.AddIncomingPlace(p4);
            tG.AddOutgoingPlace(p8);

            p5.AppendIncomingTransition(tC);
            p5.AppendOutgoingTransition(tH);
            p5.AppendOutgoingTransition(tI);

            tH.AddIncomingPlace(p5);
            tH.AddOutgoingPlace(p9);

            tI.AddIncomingPlace(p5);
            tI.AddOutgoingPlace(p9);

            p6.AppendIncomingTransition(tC);
            p6.AppendOutgoingTransition(tJ);
            p6.AppendOutgoingTransition(tK);

            tJ.AddIncomingPlace(p6);
            tJ.AddOutgoingPlace(p10);

            tK.AddIncomingPlace(p6);
            tK.AddOutgoingPlace(p10);

            p7.AppendIncomingTransition(tD);
            p7.AppendIncomingTransition(tE);
            p7.AppendOutgoingTransition(tL);

            p8.AppendIncomingTransition(tF);
            p8.AppendIncomingTransition(tG);
            p8.AppendOutgoingTransition(tL);

            tL.AddIncomingPlace(p7);
            tL.AddIncomingPlace(p8);
            tL.AddOutgoingPlace(p11);

            p9.AppendIncomingTransition(tH);
            p9.AppendIncomingTransition(tI);
            p9.AppendOutgoingTransition(tM);

            p10.AppendIncomingTransition(tJ);
            p10.AppendIncomingTransition(tK);
            p10.AppendOutgoingTransition(tM);

            tM.AddIncomingPlace(p9);
            tM.AddIncomingPlace(p10);
            tM.AddOutgoingPlace(p12);

            p11.AppendIncomingTransition(tL);
            p11.AppendOutgoingTransition(tN);

            p12.AppendIncomingTransition(tM);
            p12.AppendOutgoingTransition(tN);

            tN.AddIncomingPlace(p11);
            tN.AddIncomingPlace(p12);
            tN.AddOutgoingPlace(pEnd);

            pEnd.AppendIncomingTransition(tN);

            // Add Transitions and places to petrinet
            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);
            petriNet.Transitions.Add(tE);
            petriNet.Transitions.Add(tF);
            petriNet.Transitions.Add(tG);
            petriNet.Transitions.Add(tH);
            petriNet.Transitions.Add(tI);
            petriNet.Transitions.Add(tJ);
            petriNet.Transitions.Add(tK);
            petriNet.Transitions.Add(tL);
            petriNet.Transitions.Add(tM);
            petriNet.Transitions.Add(tN);

            petriNet.Places.Add(pStart);
            petriNet.Places.Add(p1);
            petriNet.Places.Add(p2);
            petriNet.Places.Add(p3);
            petriNet.Places.Add(p4);
            petriNet.Places.Add(p5);
            petriNet.Places.Add(p6);
            petriNet.Places.Add(p7);
            petriNet.Places.Add(p8);
            petriNet.Places.Add(p9);
            petriNet.Places.Add(p10);
            petriNet.Places.Add(p11);
            petriNet.Places.Add(p12);
            petriNet.Places.Add(pEnd);

            return petriNet;
        }
        /// <summary>
        /// Resolves a construct of three parallel events: a AND ( b XOR c )        
        /// </summary>
        /// <param name="event1">One event</param>
        /// <param name="a">An event node</param>
        /// <param name="b">An event node</param>
        /// <param name="c">An event node</param>
        /// <param name="petriNet">Current petri net</param>
        /// <returns>A list with final transitions</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAand_BxorC(Transition event1, EventNode a, EventNode b, EventNode c, PetriNet petriNet)
        {
            var finalTransition = petriNet.AddTransition("AND Join");
            finalTransition.IsANDJoin = true;

            var andTransition = StartAND(event1, new List<EventNode> { a }, petriNet);
            EndAND(andTransition, petriNet, finalTransition);

            var xorTransition = StartXOR(event1, new List<EventNode> { b, c }, petriNet);
            EndXOR(xorTransition, petriNet, finalTransition);

            return new List<Transition> { finalTransition };
        }
        /// <summary>
        ///     Draw a Rectangle
        /// </summary>
        /// <param name="transition"></param>
        /// <autor>Thomas Meents, Krystian Zielonka</autor>
        private ExtendedThumb DrawTransition(Transition transition)
        {
            String name = transition.Name.Trim();
            ExtendedThumb transitionThumb = new ExtendedThumb
            {
                Name = "Transition",
                Width = Settings.Default.TransitionWidth,
                Height = Settings.Default.TransitionHeight
            };
            transitionThumb.Margin = new Thickness(-transitionThumb.Width/2, -transitionThumb.Height/2, 0, 0);
            transitionThumb.Template = GetTransitionTemplate();

            transitionThumb.ToolTip = name;

            transitionThumb.SetValue(ContentControl.ContentProperty, name);

            ContextMenu contextMenu = new ContextMenu();
            Label labelText = new Label {Content = name};
            contextMenu.Items.Add(labelText);
            transitionThumb.ContextMenu = contextMenu;

            return transitionThumb;
        }
        /// <summary>
        /// Resolves a construct of three parallel events: a XOR ( b AND c )
        /// </summary>
        /// <param name="event1">Event number one</param>
        /// <param name="a">An Event node</param>
        /// <param name="b">An Event node</param>
        /// <param name="c">An Event node</param>
        /// <param name="petriNet">The current petri net</param>
        /// <returns>A list with final transition</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAxor_BandC(Transition event1, EventNode a, EventNode b, EventNode c, PetriNet petriNet)
        {
            var finalTransition = petriNet.AddTransition(); // empty transition, will possibly be cleaned up
            finalTransition.Name = FindFirstCommonSuccessor(new List<EventNode> { a, b, c });

            var xorTransition = StartXOR(event1, new List<EventNode> { a }, petriNet);
            EndXOR(xorTransition, petriNet, finalTransition);

            var andSplit = petriNet.AddTransition(); // no idea where this disappears...
            andSplit.AddIncomingPlace(xorTransition[0].IncomingPlaces[0]); // XOR-Split-Place

            var andTransition = StartAND(andSplit, new List<EventNode> { b, c }, petriNet);
            var andJoin = petriNet.AddTransition("AND Join");
            andJoin.IsANDJoin = true;
            var andTransition2 = EndAND(andTransition, petriNet, andJoin);

            andTransition2[0].AddOutgoingPlace(finalTransition.IncomingPlaces.FirstOrDefault());

            return new List<Transition> { finalTransition };
        }
        public void CompareEventLogAndPetriNetTest1()
        {
            //
            //EventLog
            //
            //create Case1
            Case ca1 = new Case();
            ca1.CreateEvent("A");
            ca1.CreateEvent("C");
            ca1.CreateEvent("D");
            ca1.CreateEvent("E");
            ca1.CreateEvent("H");

            //create Case2
            Case ca2 = new Case();
            ca2.CreateEvent("A");
            ca2.CreateEvent("B");
            ca2.CreateEvent("D");
            ca2.CreateEvent("E");
            ca2.CreateEvent("G");

            //create Case3
            Case ca3 = new Case();
            ca3.CreateEvent("A");
            ca3.CreateEvent("D");
            ca3.CreateEvent("C");
            ca3.CreateEvent("E");
            ca3.CreateEvent("H");

            //create Case4
            Case ca4 = new Case();
            ca4.CreateEvent("A");
            ca4.CreateEvent("B");
            ca4.CreateEvent("D");
            ca4.CreateEvent("E");
            ca4.CreateEvent("H");

            //create Case5
            Case ca5 = new Case();
            ca5.CreateEvent("A");
            ca5.CreateEvent("C");
            ca5.CreateEvent("D");
            ca5.CreateEvent("E");
            ca5.CreateEvent("G");

            //create Case6
            Case ca6 = new Case();
            ca6.CreateEvent("A");
            ca6.CreateEvent("D");
            ca6.CreateEvent("C");
            ca6.CreateEvent("E");
            ca6.CreateEvent("G");

            //create Case7
            Case ca7 = new Case();
            ca7.CreateEvent("A");
            ca7.CreateEvent("D");
            ca7.CreateEvent("B");
            ca7.CreateEvent("E");
            ca7.CreateEvent("H");

            //create Case8
            Case ca8 = new Case();
            ca8.CreateEvent("A");
            ca8.CreateEvent("C");
            ca8.CreateEvent("D");
            ca8.CreateEvent("E");
            ca8.CreateEvent("F");
            ca8.CreateEvent("D");
            ca8.CreateEvent("B");
            ca8.CreateEvent("E");
            ca8.CreateEvent("H");

            //create Case9
            Case ca9 = new Case();
            ca9.CreateEvent("A");
            ca9.CreateEvent("D");
            ca9.CreateEvent("B");
            ca9.CreateEvent("E");
            ca9.CreateEvent("G");

            //create Case10
            Case ca10 = new Case();
            ca10.CreateEvent("A");
            ca10.CreateEvent("C");
            ca10.CreateEvent("D");
            ca10.CreateEvent("E");
            ca10.CreateEvent("F");
            ca10.CreateEvent("B");
            ca10.CreateEvent("D");
            ca10.CreateEvent("E");
            ca10.CreateEvent("H");

            //create Case11
            Case ca11 = new Case();
            ca11.CreateEvent("A");
            ca11.CreateEvent("C");
            ca11.CreateEvent("D");
            ca11.CreateEvent("E");
            ca11.CreateEvent("F");
            ca11.CreateEvent("B");
            ca11.CreateEvent("D");
            ca11.CreateEvent("E");
            ca11.CreateEvent("G");

            //create Case12
            Case ca12 = new Case();
            ca12.CreateEvent("A");
            ca12.CreateEvent("C");
            ca12.CreateEvent("D");
            ca12.CreateEvent("E");
            ca12.CreateEvent("F");
            ca12.CreateEvent("D");
            ca12.CreateEvent("B");
            ca12.CreateEvent("E");
            ca12.CreateEvent("G");

            //create Case13
            Case ca13 = new Case();
            ca13.CreateEvent("A");
            ca13.CreateEvent("D");
            ca13.CreateEvent("C");
            ca13.CreateEvent("E");
            ca13.CreateEvent("F");
            ca13.CreateEvent("C");
            ca13.CreateEvent("D");
            ca13.CreateEvent("E");
            ca13.CreateEvent("H");

            //create Case14
            Case ca14 = new Case();
            ca14.CreateEvent("A");
            ca14.CreateEvent("D");
            ca14.CreateEvent("C");
            ca14.CreateEvent("E");
            ca14.CreateEvent("F");
            ca14.CreateEvent("D");
            ca14.CreateEvent("B");
            ca14.CreateEvent("E");
            ca14.CreateEvent("H");

            //create Case15
            Case ca15 = new Case();
            ca15.CreateEvent("A");
            ca15.CreateEvent("D");
            ca15.CreateEvent("C");
            ca15.CreateEvent("E");
            ca15.CreateEvent("F");
            ca15.CreateEvent("B");
            ca15.CreateEvent("D");
            ca15.CreateEvent("E");
            ca15.CreateEvent("G");

            //create Case16
            Case ca16 = new Case();
            ca16.CreateEvent("A");
            ca16.CreateEvent("C");
            ca16.CreateEvent("D");
            ca16.CreateEvent("E");
            ca16.CreateEvent("F");
            ca16.CreateEvent("B");
            ca16.CreateEvent("D");
            ca16.CreateEvent("E");
            ca16.CreateEvent("F");
            ca16.CreateEvent("D");
            ca16.CreateEvent("B");
            ca16.CreateEvent("E");
            ca16.CreateEvent("G");

            //create Case17
            Case ca17 = new Case();
            ca17.CreateEvent("A");
            ca17.CreateEvent("D");
            ca17.CreateEvent("C");
            ca17.CreateEvent("E");
            ca17.CreateEvent("F");
            ca17.CreateEvent("D");
            ca17.CreateEvent("B");
            ca17.CreateEvent("E");
            ca17.CreateEvent("G");

            //create Case18
            Case ca18 = new Case();
            ca18.CreateEvent("A");
            ca18.CreateEvent("D");
            ca18.CreateEvent("C");
            ca18.CreateEvent("E");
            ca18.CreateEvent("F");
            ca18.CreateEvent("B");
            ca18.CreateEvent("D");
            ca18.CreateEvent("E");
            ca18.CreateEvent("F");
            ca18.CreateEvent("B");
            ca18.CreateEvent("D");
            ca18.CreateEvent("E");
            ca18.CreateEvent("G");

            //create Case19
            Case ca19 = new Case();
            ca19.CreateEvent("A");
            ca19.CreateEvent("D");
            ca19.CreateEvent("C");
            ca19.CreateEvent("E");
            ca19.CreateEvent("F");
            ca19.CreateEvent("D");
            ca19.CreateEvent("B");
            ca19.CreateEvent("E");
            ca19.CreateEvent("F");
            ca19.CreateEvent("B");
            ca19.CreateEvent("D");
            ca19.CreateEvent("E");
            ca19.CreateEvent("H");

            //create Case20
            Case ca20 = new Case();
            ca20.CreateEvent("A");
            ca20.CreateEvent("D");
            ca20.CreateEvent("B");
            ca20.CreateEvent("E");
            ca20.CreateEvent("F");
            ca20.CreateEvent("B");
            ca20.CreateEvent("D");
            ca20.CreateEvent("E");
            ca20.CreateEvent("F");
            ca20.CreateEvent("D");
            ca20.CreateEvent("B");
            ca20.CreateEvent("E");
            ca20.CreateEvent("G");

            //create Case21
            Case ca21 = new Case();
            ca21.CreateEvent("A");
            ca21.CreateEvent("D");
            ca21.CreateEvent("C");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("D");
            ca21.CreateEvent("B");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("C");
            ca21.CreateEvent("D");
            ca21.CreateEvent("E");
            ca21.CreateEvent("F");
            ca21.CreateEvent("D");
            ca21.CreateEvent("B");
            ca21.CreateEvent("E");
            ca21.CreateEvent("G");

            //create Event Log
            EventLog eventLog = new EventLog();
            eventLog.Cases.Add(ca1);
            eventLog.Cases.Add(ca2);
            eventLog.Cases.Add(ca3);
            eventLog.Cases.Add(ca4);
            eventLog.Cases.Add(ca5);
            eventLog.Cases.Add(ca6);
            eventLog.Cases.Add(ca7);
            eventLog.Cases.Add(ca8);
            eventLog.Cases.Add(ca9);
            eventLog.Cases.Add(ca10);
            eventLog.Cases.Add(ca11);
            eventLog.Cases.Add(ca12);
            eventLog.Cases.Add(ca13);
            eventLog.Cases.Add(ca14);
            eventLog.Cases.Add(ca15);
            eventLog.Cases.Add(ca16);
            eventLog.Cases.Add(ca17);
            eventLog.Cases.Add(ca18);
            eventLog.Cases.Add(ca19);
            eventLog.Cases.Add(ca20);
            eventLog.Cases.Add(ca21);

            //
            //PetriNet
            //
            PetriNet petriNet = new PetriNet("Petri-Net Name");

            Place pStart = new Place("Place Start", 0);
            Place pC1 = new Place("c1", 0);
            Place pC2 = new Place("c2", 0);
            Place pC3 = new Place("c3", 0);
            Place pC4 = new Place("c4", 0);
            Place pC5 = new Place("c5", 0);
            Place pEnd = new Place("Place End", 0);

            Transition tA = new Transition("A");
            Transition tB = new Transition("B");
            Transition tC = new Transition("C");
            Transition tD = new Transition("D");
            Transition tE = new Transition("E");
            Transition tF = new Transition("F");
            Transition tG = new Transition("G");
            Transition tH = new Transition("H");

            tG.AddOutgoingPlace(pEnd);
            tG.AddIncomingPlace(pC5);

            tH.AddOutgoingPlace(pEnd);
            tH.AddIncomingPlace(pC5);

            tE.AddIncomingPlace(pC3);
            tE.AddIncomingPlace(pC4);
            tE.AddOutgoingPlace(pC5);

            pC3.AppendIncomingTransition(tB);
            pC3.AppendIncomingTransition(tC);
            pC3.AppendOutgoingTransition(tE);

            pC4.AppendIncomingTransition(tD);
            pC4.AppendOutgoingTransition(tE);

            tB.AddIncomingPlace(pC1);
            tB.AddOutgoingPlace(pC3);

            tC.AddIncomingPlace(pC1);
            tC.AddOutgoingPlace(pC3);

            tD.AddIncomingPlace(pC2);
            tD.AddOutgoingPlace(pC4);

            pC1.AppendIncomingTransition(tA);
            pC1.AppendOutgoingTransition(tB);
            pC1.AppendOutgoingTransition(tC);

            pC2.AppendIncomingTransition(tA);
            pC2.AppendOutgoingTransition(tD);

            tF.AddIncomingPlace(pC5);
            tF.AddOutgoingPlace(pC1);
            tF.AddOutgoingPlace(pC2);

            //
            tA.AddIncomingPlace(pStart);
            tA.AddOutgoingPlace(pC1);
            tA.AddOutgoingPlace(pC2);

            pStart.AppendOutgoingTransition(tA);

            pEnd.AppendIncomingTransition(tG);
            pEnd.AppendIncomingTransition(tH);

            ////
            petriNet.Transitions.Add(tA);
            petriNet.Transitions.Add(tB);
            petriNet.Transitions.Add(tC);
            petriNet.Transitions.Add(tD);
            petriNet.Transitions.Add(tE);
            petriNet.Transitions.Add(tF);
            petriNet.Transitions.Add(tG);
            petriNet.Transitions.Add(tH);

            ////
            petriNet.Places.Add(pStart);
            petriNet.Places.Add(pC1);
            petriNet.Places.Add(pC2);
            petriNet.Places.Add(pC3);
            petriNet.Places.Add(pC4);
            petriNet.Places.Add(pC5);
            petriNet.Places.Add(pEnd);

            ComparingFootprint footprintEventLog = ComparingFootprintAlgorithm.CreateFootprint(eventLog);
            ComparingFootprint footprintPetriNet = ComparingFootprintAlgorithm.CreateFootprint(petriNet);

            ComparingFootprintResultMatrix footprintResultMatrix = new ComparingFootprintResultMatrix(footprintEventLog, footprintPetriNet);

            if (footprintResultMatrix.HeaderWithEventNames.Count != 8)
            {
                Assert.Fail("");
            }

            int y = 0;
            foreach (String headerNameY in footprintResultMatrix.HeaderWithEventNames)
            {
                int x = 0;
                foreach (String headerNameX in footprintResultMatrix.HeaderWithEventNames)
                {
                    ResultCellType resultCellType = footprintResultMatrix.ResultMatrix[y, x];
                    Console.WriteLine("Test headerNameY: " + headerNameY + ", headerNameX: " + headerNameX + " [" + y + "," + x + "].CellType:" + resultCellType);

                    if (!resultCellType.Equals(ResultCellType.NoDifferences))
                    {
                        Assert.Fail("Test headerNameY: " + headerNameY + ", headerNameX: " + headerNameX + " [" + y + "," + x + "].CellType:" + resultCellType);
                    }

                    x++;
                }
                y++;
            }

            //Arrange (Create Footprints)
            ComparingFootprint footPrintEventlog = ComparingFootprintAlgorithm.CreateFootprint(eventLog);
            ComparingFootprint footPrintPetrinet = ComparingFootprintAlgorithm.CreateFootprint(petriNet);
            ComparingFootprintResultMatrix resultFootprint = new ComparingFootprintResultMatrix(footPrintEventlog, footPrintPetrinet);

            // Act (Calculate Fitness)
            double fitnessComparingFootprint = ComparingFootprintAlgorithm.CalculateFitness(resultFootprint.GetNumberOfDifferences(), resultFootprint.GetNumberOfOpportunities());

            if (fitnessComparingFootprint != 1.0)
            {
                // Assert
                Assert.Fail("Fitness not correct! (" + fitnessComparingFootprint + ")");
            }
        }
        /// <summary>
        /// Adds a place and the transitions it leads to.
        /// </summary>
        /// <param name="startingTransition">>Contains the starting transition</param>
        /// <param name="followers">node.followers</param>
        /// <param name="petriNet">Contains the current petri net</param>
        /// <returns>The two transitions that are in an XOR-relation.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartXOR(Transition startingTransition, List<EventNode> followers, PetriNet petriNet)
        {
            if (followers.Count > 1)
                for (var index = 0; index < followers.Count; index++)
                    _openParallelismCount.Push(Parallelism.Xor);

            var newPlace = petriNet.AddPlace();
            var listOfFollowingTransitions = new List<Transition>();
            foreach (var eventNode in followers)
            {
                if (eventNode == null)
                    break;
                /* _____________________          __________         ____________________________
                 * | startingTransition |  --->  ( NewPlace )  --->  |  NewFollowingTransition  |
                 * '''''''''''''''''''''          **********         ''''''''''''''''''''''''''''
                 */
                var newFollowingTransition = petriNet.FindTransition(eventNode.InnerEvent.Name);
                // The following transition already exists => close something
                if (newFollowingTransition != null)
                {
                    if (_openParallelismCount.Count > 0)
                        switch (_openParallelismCount.Peek())
                        {
                            // Close XOR
                            case Parallelism.Xor:
                                newFollowingTransition.IncomingPlaces.Remove(newPlace);
                                startingTransition.AddOutgoingPlace(newFollowingTransition.IncomingPlaces.First());
                                _openParallelismCount.Pop();
                                break;
                            // Close AND
                            case Parallelism.And:
                                newFollowingTransition.AddIncomingPlace(newPlace);
                                startingTransition.AddOutgoingPlace(newPlace);
                                _openParallelismCount.Pop();
                                break;
                        }
                }
                // Open XOR
                else
                {
                    newFollowingTransition = petriNet.AddTransition(eventNode.InnerEvent.Name, incomingPlace: newPlace);
                    if (newPlace.IncomingTransitions.Count == 0)
                        startingTransition.AddOutgoingPlace(newPlace);
                }

                listOfFollowingTransitions.Add(newFollowingTransition);

            }
            if (newPlace.IncomingTransitions.Count == 0 && newPlace.OutgoingTransitions.Count == 0)
                petriNet.Places.Remove(newPlace);
            return listOfFollowingTransitions;
        }
 /// <summary>
 /// Returns a generated TransitionID
 /// </summary>
 /// <param name="transition"></param>
 /// <returns></returns>
 /// <autor>Andrej Albrecht</autor>
 public String GetTransitionID(Transition transition)
 {
     return "t" + Transitions.IndexOf(transition);
 }