public void Count_TwoEquivalenceClasses_ReturnsTotalNumberOfItems() { var queue = new FastEquivalenceQueue <int>(new ModuloIntegerEqualityComparer(2)); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); Assert.AreEqual(3, queue.Count); }
public void DequeueEquivalenceSet_EqueueNonUniqueItem_EnqueuesOnlyOnce() { var queue = new FastEquivalenceQueue <int>(EqualityComparer <int> .Default); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(1); var result = queue.DequeueEquivalenceSet().ToList(); Assert.AreEqual(1, result.Count); }
public void DequeueEquivalenceSet_TwoEquivalenceClasses_ReturnsOnlyItemsFromFirstClass() { var queue = new FastEquivalenceQueue <int>(new ModuloIntegerEqualityComparer(2)); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); queue.Enqueue(4); var result = queue.DequeueEquivalenceSet().ToList(); Assert.That(result, Is.EquivalentTo(new[] { 1, 3 })); }
public void IsEmpty_NotEmptyQueue_ReturnsFalse() { var queue = new FastEquivalenceQueue <int>(new ModuloIntegerEqualityComparer(3, 2)); queue.Enqueue(2); Assert.IsFalse(queue.IsEmpty); }
public void Equeue_EqueueOne_Enqueues() { var queue = new FastEquivalenceQueue <int>(EqualityComparer <int> .Default); queue.Enqueue(1); var result = queue.DequeueEquivalenceSet().ToList(); Assert.AreEqual(1, result.Single()); }
public void DequeueEquivalenceSet_ThreeEquivalenceClassesWithTwoHashesThirdDequeue_ReturnsOnlyItemsFromThirdClass() { var queue = new FastEquivalenceQueue <int>(new ModuloIntegerEqualityComparer(3, 2)); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); queue.Enqueue(4); queue.Enqueue(5); queue.Enqueue(6); var a = queue.DequeueEquivalenceSet(); var b = queue.DequeueEquivalenceSet(); var result = queue.DequeueEquivalenceSet().ToList(); Assert.That(result, Is.EquivalentTo(new[] { 3, 6 })); }
/// <summary> /// Optimizes the specified input machine. /// </summary> /// <param name="inputMachine">The input machine. Must have transitions in a common order. Must be in format as generated by the <see cref="StateMachineBuilder"/> (no loops other than regular back-transitions within a single path).</param> /// <returns>State machine with all equivalent states merged into one state.</returns> public StateMachine OptimizeSortedMachine(StateMachine inputMachine) { var parentStateMap = this.BuildParentStateMap(inputMachine); var finalStates = this.GetFinalStates(inputMachine); var transitionComparer = new TransitionNonrecursiveEqualityComparer(); var queue = new FastEquivalenceQueue <State>(new TransitionCountStateEqualityComparer()); var oldToNewMap = new Dictionary <State, State>(); var waitingForBacktransitionConfirmationMap = new Dictionary <State, WaitingForConfirmationInfo>(); var backtTransitionsByState = this.GetBackTransitionsByState(inputMachine); foreach (var finalState in finalStates) { queue.Enqueue(finalState); } //int i = 0; while (!queue.IsEmpty) { //i++; var currentSet = queue.DequeueEquivalenceSet().ToList(); /*Console.WriteLine("======================="); * Console.WriteLine(i + " T " + queue.Count + ") " + string.Join(", ", currentSet.Select(p => p)));*/ // First state is the "template" for the equivalency class (all the other states in the group have to be equivalent // to this state to be in its group) var firstState = currentSet.First(); foreach (var state in currentSet) { //Console.WriteLine("Current: " + state); // If the previous template state was kicked out due to not having all its children processed, // try to use the next state as a template. if (firstState == null) { firstState = state; } var currentStateBackTransition = backtTransitionsByState.GetValueOrDefault(state); var firstStateBackTransition = backtTransitionsByState.GetValueOrDefault(firstState); // Were all children of this state already processed? (skip back-transitions) if (!state.Transitions.Where(p => currentStateBackTransition != p).All(p => oldToNewMap.ContainsKey(p.TargetState))) { // Another state will have to become the template. if (state == firstState) { firstState = null; } //Console.WriteLine("Requeueing because children not processed"); queue.Enqueue(state); continue; } // By now, at least one state is still in the equivalency class (and is the template). // The template is obviously auto-included in the group. if (firstState != state) { if (firstState.Transitions.Count != state.Transitions.Count) { //Console.WriteLine("Requeueing because not same number of transitions as template"); queue.Enqueue(state); continue; } // Do a rough check of the back-transition (we can discard obviously non-equivalent back-transitions) if ( !transitionComparer.Equals(currentStateBackTransition, firstStateBackTransition) || ((currentStateBackTransition != null) != (firstStateBackTransition != null))) { //Console.WriteLine("Requeueing because preliminary backtransition check failed"); queue.Enqueue(state); continue; } // Check if the children states of the current state (and transitions leading to them) match the template. var transitionPairs = state.Transitions.Where(p => currentStateBackTransition != p).Zip( firstState.Transitions.Where(p => backtTransitionsByState.GetValueOrDefault(firstState) != p), (currentStateTransition, firstStateTransition) => new { currentStateTransition, firstStateTransition } ); if (transitionPairs.Any(pair => { //Console.WriteLine("Compare transition: first " + pair.firstStateTransition.SortingKey + " current" + pair.firstStateTransition.SortingKey); // The transitions must match either way (whether there is backtransition going around current state or not). if (!transitionComparer.Equals(pair.currentStateTransition, pair.firstStateTransition)) { return(true); } var waitingForConfirmationFirstStateInfo = waitingForBacktransitionConfirmationMap.GetValueOrDefault(pair.firstStateTransition.TargetState); var waitingForConfirmationCurrentStateInfo = waitingForBacktransitionConfirmationMap.GetValueOrDefault(pair.currentStateTransition.TargetState); /*Console.WriteLine( * "Waiting template: first " + * (waitingForConfirmationFirstStateInfo != null ? * waitingForConfirmationFirstStateInfo.TemplateState.HeadShift.ToString() : "x") + * " current " + * (waitingForConfirmationCurrentStateInfo != null ? * waitingForConfirmationCurrentStateInfo.TemplateState.HeadShift.ToString() : "x"));*/ if (waitingForConfirmationFirstStateInfo == null && waitingForConfirmationCurrentStateInfo == null) { return(oldToNewMap[pair.firstStateTransition.TargetState] != oldToNewMap[pair.currentStateTransition.TargetState]); } else if (waitingForConfirmationFirstStateInfo == null || waitingForConfirmationCurrentStateInfo == null) { return(true); } else { // Equivalent template state in the waiting-for-conf info means the children were processed and that they are equivalent. return(waitingForConfirmationFirstStateInfo.TemplateState != waitingForConfirmationCurrentStateInfo.TemplateState); } } //oldToNewMap[pair.firstStateTransition.TargetState] != oldToNewMap[pair.currentStateTransition.TargetState] /*&& //waitingForBacktransitionConfirmationMap.GetValueOrDefault().TemplateState )) { //Console.WriteLine("Requeueing because children (or transitions to children) don't match"); queue.Enqueue(state); continue; } } // Were children of this state waiting for backtransition confirmation? // TODO: Check if children are waiting for the same state (opposite would mean a bug in Compiler) var childrenWaitingForConfirmationInfo = state.Transitions .Where(p => currentStateBackTransition != p && waitingForBacktransitionConfirmationMap.ContainsKey(p.TargetState)) .Select(p => p.TargetState) .Select(childState => waitingForBacktransitionConfirmationMap[childState]) .ToList(); // If there is a backtransition loop going from this state to this state, consider the state to be a child of itself for purpose // of back-transition handling (to avoid having to handle this as a special case later). var hasSelfBacktransition = currentStateBackTransition != null && currentStateBackTransition.TargetState == state; if (hasSelfBacktransition) { childrenWaitingForConfirmationInfo.Add(new WaitingForConfirmationInfo { TemplateState = firstState, ConfirmingState = state, StatesWithBacktransitions = new List <State> { state } }); } /*Console.WriteLine("Following waiting for confirmation infos were passed by children:"); * foreach (var waitingForConfirmationInfo in childrenWaitingForConfirmationInfo) * { * Console.WriteLine("\t" + waitingForConfirmationInfo); * }*/ var isWaitingBacktransitionTarget = childrenWaitingForConfirmationInfo.Count > 0 && childrenWaitingForConfirmationInfo.First().ConfirmingState == state; /*Console.WriteLine("Reuse template?"); * Console.WriteLine("\tIs NOT the template:" + (state != firstState)); * Console.WriteLine("\tHas no backtransition:" + (currentStateBackTransition == null) + " OR it is self-backtransition :" + hasSelfBacktransition); * Console.WriteLine("\tChildren have no open backtransitions:" + (childrenWaitingForConfirmationInfo.Count == 0) + " OR It is the target :" + isWaitingBacktransitionTarget);*/ // Merge this state's subtree into the template state's subtree, if it matches following conditions State newState; if ( state != firstState && // Always create a new subree for the template state. (currentStateBackTransition == null || hasSelfBacktransition) && // If the state has backtransition, it must its target. (childrenWaitingForConfirmationInfo.Count == 0 || isWaitingBacktransitionTarget) // There are no backtransitions going around it ) { newState = oldToNewMap[firstState]; //Console.WriteLine("Reusing template"); } else { newState = new State(); newState.Transitions = state.Transitions.Where(p => p != currentStateBackTransition).Select(t => { var newTransition = t.Clone(); newTransition.TargetState = oldToNewMap[t.TargetState]; return(newTransition); }).ToList(); //Console.WriteLine("Creating new state"); } oldToNewMap[state] = newState; if (currentStateBackTransition != null && currentStateBackTransition.TargetState != state) { waitingForBacktransitionConfirmationMap.Add( state, new WaitingForConfirmationInfo { ConfirmingState = currentStateBackTransition.TargetState, TemplateState = firstState, StatesWithBacktransitions = new List <State> { state } }); //Console.WriteLine("wrote waiting for template " + firstState + " because has backtrans"); } if (childrenWaitingForConfirmationInfo.Count > 0) { if (!isWaitingBacktransitionTarget && currentStateBackTransition == null /*!stateComparer.Equals(childrenWaitingForConfirmationInfo.First().ConfirmingState, state)*/) // TODO: Co tady? { // This is not the state these states are waiting for -> forward the waiting for confirmation info further waitingForBacktransitionConfirmationMap.Add( state, new WaitingForConfirmationInfo { ConfirmingState = childrenWaitingForConfirmationInfo.First().ConfirmingState, TemplateState = firstState, StatesWithBacktransitions = childrenWaitingForConfirmationInfo.SelectMany(p => p.StatesWithBacktransitions).ToList() }); //Console.WriteLine("wrote waiting for template " + firstState + " not which waiting for"); } else { // This is the state the unconfirmed states are waiting for! // Add back-transitions from these states to the current state. foreach (var stateWaitingForBacktransition in childrenWaitingForConfirmationInfo.SelectMany(p => p.StatesWithBacktransitions)) { var backTransitionOrigin = oldToNewMap[stateWaitingForBacktransition]; backTransitionOrigin.Transitions.Add(new AlwaysTransition { TargetState = newState, HeadShift = backTransitionOrigin == newState ? 1 : 0 // Do not loop in place }); } //Console.WriteLine("skipped forwarding waiting for template " + firstState + " , is backtrans target (backtrans created)"); } } foreach (var parentState in parentStateMap[state]) { // Parent map also includes backtransition -> exclude them now. var parentBackTransition = backtTransitionsByState.GetValueOrDefault(parentState); if (parentBackTransition != null && parentBackTransition.TargetState == state) { continue; } //Console.WriteLine("Enqueued parent state " + parentState); // Tady bude treba resit, aby se do fronty vrcholy nepridavaly vicekrat queue.Enqueue(parentState); } } } return(new StateMachine(oldToNewMap[inputMachine.EntryState])); }