private bool CanTransitionsBeMerged(LtmcTransition *a, LtmcTransition *b) { var aToStuttering = TransitionFlags.IsToStutteringState(a->Flags); var bToStuttering = TransitionFlags.IsToStutteringState(b->Flags); if (aToStuttering != bToStuttering) { // Target states do not match return(false); } if (!aToStuttering) { // both target states are not the stuttering state. So check if the states match if (!MemoryBuffer.AreEqual(a->TargetStatePointer, b->TargetStatePointer, RelevantStateVectorSize)) { return(false); } } if (a->Flags != b->Flags) { return(false); } if (a->Formulas != b->Formulas) { return(false); } return(true); }
/// <summary> /// Optionally modifies the <paramref name="transitions" />, changing any of their values. However, no new transitions can be /// added; transitions can be removed by setting their <see cref="CandidateTransition.IsValid" /> flag to <c>false</c>. /// During subsequent traversal steps, only valid transitions and target states reached by at least one valid transition /// are considered. /// </summary> /// <param name="context">The context of the model traversal.</param> /// <param name="worker">The worker that found the transition.</param> /// <param name="transitions">The transitions that should be checked.</param> /// <param name="sourceState">The source state of the transitions.</param> /// <param name="sourceStateIndex">The unique index of the transition's source state.</param> /// <param name="isInitial">Indicates whether the transitions are initial transitions not starting in any valid source state.</param> public void ModifyTransitions(TraversalContext <TExecutableModel> context, Worker <TExecutableModel> worker, TransitionCollection transitions, byte *sourceState, int sourceStateIndex, bool isInitial) { foreach (CandidateTransition *transition in transitions) { transition->Flags = TransitionFlags.SetIsValidIffCondition(transition->Flags, transition->ActivatedFaults.GetIntersection(_suppressedFaults).IsEmpty); } }
/// <summary> /// Returns the target state if the transition has been transformed by Worker::HandleTransitions. /// </summary> public int GetTargetStateIndex() { Assert.That(TransitionFlags.IsStateTransformedToIndex(Flags), "Transition must be transformed first"); fixed(byte **addr = &TargetStatePointer) { return(*((int *)addr + 1)); //second four bytes of FieldOffset(0) } }
/// <summary> /// Optionally modifies the <paramref name="transitions" />, changing any of their values. However, no new transitions can be /// added; transitions can be removed by setting their <see cref="CandidateTransition.IsValid" /> flag to <c>false</c>. /// During subsequent traversal steps, only valid transitions and target states reached by at least one valid transition /// are considered. /// </summary> /// <param name="context">The context of the model traversal.</param> /// <param name="worker">The worker that found the transition.</param> /// <param name="transitions">The transitions that should be checked.</param> /// <param name="sourceState">The source state of the transitions.</param> /// <param name="sourceStateIndex">The unique index of the transition's source state.</param> /// <param name="isInitial">Indicates whether the transitions are initial transitions not starting in any valid source state.</param> public void ModifyTransitions(TraversalContext context, Worker worker, TransitionCollection transitions, byte *sourceState, int sourceStateIndex, bool isInitial) { foreach (CandidateTransition *transition in transitions) { if (TransitionFlags.IsValid(transition->Flags) && _terminateEarlyCondition(transition->Formulas)) { transition->Flags = TransitionFlags.SetToStutteringStateFlag(transition->Flags); } } }
private void IterateThroughAllTransitionsInSortedOrder() { var mergeInCandidateIndex = 0; while (mergeInCandidateIndex < _transitions.Count) { var mergeInCandidate = GetCandidateTransition(mergeInCandidateIndex); if (TransitionFlags.IsValid(mergeInCandidate->Flags)) { MergeCandidateWithAllApplicableTargets(mergeInCandidate, mergeInCandidateIndex); } mergeInCandidateIndex++; } }
/// <summary> /// Advances the enumerator to the next element of the collection. /// </summary> public bool MoveNext() { ++_current; while (_current < _count) { if (TransitionFlags.IsValid(Current->Flags)) { return(true); } ++_current; } return(false); }
private uint HashTransition(LtmcTransition *transition) { // hashing see FNV hash at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx if (!TransitionFlags.IsValid(transition->Flags)) { return(0); } unchecked { uint hash = 0; if (!TransitionFlags.IsToStutteringState(transition->Flags)) { hash = MemoryBuffer.Hash(transition->TargetStatePointer, RelevantStateVectorSize, 0); } hash = hash * 397 ^ (uint)transition->Formulas.GetHashCode(); return(hash); } }
private void MergeCandidateWithAllApplicableTargets(LtmcTransition *mergeInCandidate, int mergeInCandidateIndex) { var mergeInCandidateHash = GetCandidateHash(mergeInCandidateIndex); var toMergeCandidateIndex = mergeInCandidateIndex + 1; while (!CandidateIsOutOfIndexOrHasDifferentHash(mergeInCandidateHash, toMergeCandidateIndex)) { var toMergeCandidate = GetCandidateTransition(toMergeCandidateIndex); if (TransitionFlags.IsValid(toMergeCandidate->Flags)) { if (CanTransitionsBeMerged(mergeInCandidate, toMergeCandidate)) { MergeTransitions(mergeInCandidate, toMergeCandidate); } } toMergeCandidateIndex++; } }
/// <summary> /// Adds the <paramref name="sourceState" /> and all of its <see cref="transitions" /> to the state graph. /// </summary> /// <param name="sourceState">The state that should be added.</param> /// <param name="isInitial">Indicates whether the state is an initial state.</param> /// <param name="transitions">The transitions leaving the state.</param> /// <param name="transitionCount">The number of valid transitions leaving the state.</param> internal void AddStateInfo(int sourceState, bool isInitial, TransitionCollection transitions, int transitionCount) { Assert.That(transitionCount > 0, "Cannot add deadlock state."); Dictionary <EnrichedTargetState, double> container; if (isInitial) { container = _initialStates; } else { if (_transitions.ContainsKey(sourceState)) { container = _transitions[sourceState]; } else { container = new Dictionary <EnrichedTargetState, double>(); _transitions[sourceState] = container; } } // Search for place to append is linear in number of existing transitions of state linearly => O(n^2) foreach (var transition in transitions) { var probTransition = (LtmcTransition *)transition; Assert.That(TransitionFlags.IsValid(probTransition->Flags), "Attempted to add an invalid transition."); var enrichedTargetState = new EnrichedTargetState(transition->TargetStateIndex, transition->Formulas); if (container.ContainsKey(enrichedTargetState)) { //Case 1: Merge var currentProbability = container[enrichedTargetState]; container[enrichedTargetState] = currentProbability + probTransition->Probability; } else { //Case 2: Append container.Add(enrichedTargetState, probTransition->Probability); } } }
/// <summary> /// Adds the <paramref name="state" /> and all of its <see cref="transitions" /> to the state graph. /// </summary> /// <param name="state">The state that should be added.</param> /// <param name="isInitial">Indicates whether the state is an initial state.</param> /// <param name="transitions">The transitions leaving the state.</param> /// <param name="transitionCount">The number of valid transitions leaving the state.</param> internal void AddStateInfo(int state, bool isInitial, TransitionCollection transitions, int transitionCount) { Assert.That(!isInitial || _initialTransitionCount == 0, "Initial transitions can only be added once."); if (isInitial) { _initialTransitionCount = transitionCount; } else { Interlocked.Increment(ref _stateCount); } Interlocked.Add(ref _transitionCount, transitionCount); // Transitions are synchronized by atomatically incrementing the offset counter var offset = InterlockedExtensions.AddFetch(ref _transitionOffset, transitionCount); if (offset + transitionCount > _transitionCapacity) { throw new OutOfMemoryException("Unable to store transitions. Try increasing the transition capacity."); } // No need to synchronize state addition, as all states are only discovered once if (!isInitial) { _stateMap[state] = new TransitionRange { StartIndex = offset, Count = transitionCount } } ; // Copy the transitions into the buffer foreach (var transition in transitions) { Assert.That(TransitionFlags.IsValid(transition->Flags), "Attempted to add an invalid transition."); MemoryBuffer.Copy((byte *)transition, _transitions + offset * TransitionSize, TransitionSize); ++offset; } }
/// <summary> /// Removes all transitions that are no longer activation minimal due to the current transition. /// </summary> private void CleanupTransitions(FaultSet activatedFaults, int faultIndex, long stateHash) { var current = faultIndex; var nextPointer = &_lookup[stateHash]; while (current != -1) { var faultSet = &_faults[current]; // Remove the fault set and the corresponding transition if it is a proper subset of the activated faults if (activatedFaults.IsSubsetOf(faultSet->Transition->ActivatedFaults) && activatedFaults != faultSet->Transition->ActivatedFaults) { faultSet->Transition->Flags = TransitionFlags.RemoveValid(faultSet->Transition->Flags); *nextPointer = faultSet->NextSet; } if (nextPointer != &_lookup[stateHash]) { nextPointer = &faultSet->NextSet; } current = faultSet->NextSet; } }
/// <summary> /// Optionally modifies the <paramref name="transitions" />, changing any of their values. However, no new transitions can be /// added; transitions can be removed by setting their <see cref="CandidateTransition.IsValid" /> flag to <c>false</c>. /// During subsequent traversal steps, only valid transitions and target states reached by at least one valid transition /// are considered. /// </summary> /// <param name="context">The context of the model traversal.</param> /// <param name="worker">The worker that found the transition.</param> /// <param name="transitions">The transitions that should be checked.</param> /// <param name="sourceState">The source state of the transitions.</param> /// <param name="sourceStateIndex">The unique index of the transition's source state.</param> /// <param name="isInitial">Indicates whether the transitions are initial transitions not starting in any valid source state.</param> public void ModifyTransitions(TraversalContext <TExecutableModel> context, Worker <TExecutableModel> worker, TransitionCollection transitions, byte *sourceState, int sourceStateIndex, bool isInitial) { // The fault order state is encoded into the first four bytes of the state vector (must be four bytes as required by // RuntimeModel's state header field) var state = isInitial ? State.NeitherFaultActivated : *(State *)sourceState; foreach (CandidateTransition *transition in transitions) { var activatedFaults = transition->ActivatedFaults; var isValid = true; var nextState = state; switch (state) { case State.NeitherFaultActivated: if (activatedFaults.Contains(_firstFault) && activatedFaults.Contains(_secondFault)) { if (_forceSimultaneous) { nextState = State.BothFaultsActivated; } else { isValid = false; } } else if (activatedFaults.Contains(_firstFault)) { if (_forceSimultaneous) { isValid = false; } else { nextState = State.FirstFaultActivated; } } else if (activatedFaults.Contains(_secondFault)) { isValid = false; } break; case State.FirstFaultActivated: if (activatedFaults.Contains(_secondFault)) { nextState = State.BothFaultsActivated; } break; case State.BothFaultsActivated: break; default: Assert.NotReached("Unexpected state value."); break; } transition->Flags = TransitionFlags.SetIsValidIffCondition(transition->Flags, isValid); *(State *)transition->TargetStatePointer = nextState; } }
/// <summary> /// Handles the <paramref name="transitions" />, adding newly discovered states so that they are not visited again. /// </summary> private void HandleTransitions(TransitionCollection transitions, int sourceState, bool isInitial) { try { var transitionCount = 0; var stateCount = 0; foreach (var modifier in _transitionModifiers) { modifier.ModifyTransitions(_context, this, transitions, _context.States[sourceState], sourceState, isInitial); } _stateStack.PushFrame(); foreach (var transition in transitions) { int targetState; bool isNewState; if (TransitionFlags.IsToStutteringState(((CandidateTransition *)transition)->Flags)) { isNewState = false; targetState = _context.StutteringStateIndex; } else { isNewState = _context.States.AddState(((CandidateTransition *)transition)->TargetStatePointer, out targetState); } // Replace the CandidateTransition.TargetState pointer with the unique indexes of the transition's source and target states transition->TargetStateIndex = targetState; transition->SourceStateIndex = sourceState; transition->Flags = TransitionFlags.SetIsStateTransformedToIndexFlag(transition->Flags); if (isNewState) { ++stateCount; _stateStack.PushState(targetState); foreach (var action in _stateActions) { action.ProcessState(_context, this, _context.States[targetState], targetState, isInitial); } } foreach (var action in _transitionActions) { action.ProcessTransition(_context, this, transition, isInitial); } ++transitionCount; } Interlocked.Add(ref _context.StateCount, stateCount); Interlocked.Add(ref _context.TransitionCount, transitionCount); Interlocked.Add(ref _context.ComputedTransitionCount, transitions.TotalCount); foreach (var action in _batchedTransitionActions) { action.ProcessTransitions(_context, this, sourceState, transitions, transitionCount, isInitial); } } catch (Exception e) { _context.LoadBalancer.Terminate(); _context.Exception = e; if (!(e is OutOfMemoryException)) { CreateCounterExample(endsWithException: true, addAdditionalState: false); } } }
private void MergeTransitions(LtmcTransition *mergeInCandidate, LtmcTransition *toMergeCandidate) { mergeInCandidate->Probability += toMergeCandidate->Probability; toMergeCandidate->Flags = TransitionFlags.RemoveValid(toMergeCandidate->Flags); }
private void CheckIfTransitionIsValid(LtmcTransition *transition) { Assert.That(TransitionFlags.IsValid(transition->Flags), "Attempted to add an invalid transition."); }