예제 #1
0
        private Dictionary <int, ReachabilityStatus> ApplyTransitionToReachabilityDictionary(Dictionary <int, ReachabilityStatus> reachabilityDictionary,
                                                                                             char symbol, bool includeEpsilon)
        {
            var newReachabilityDictionary = new Dictionary <int, ReachabilityStatus>();

            foreach (var reachbilityLookup in reachabilityDictionary)
            {
                IEnumerable <KeyValuePair <int, ReachabilityStatus> > reachableStates = null !;
                if (includeEpsilon)
                {
                    reachableStates = _outgoingTransitionLookup[reachbilityLookup.Key].GetTransitionDictionary(symbol);
                }
                else
                {
                    reachableStates = _automaton.TransitionMatrix.GetStates(reachbilityLookup.Key, symbol).Select(s =>
                                                                                                                  KeyValuePair.Create(s, ReachabilityStatus.Even()));
                }

                foreach (var state in reachableStates)
                {
                    var newReachability = state.Value.Times(reachbilityLookup.Value);
                    if (!newReachabilityDictionary.TryGetValue(state.Key, out var newStatereachabilityStatus))
                    {
                        newStatereachabilityStatus           = new ReachabilityStatus();
                        newReachabilityDictionary[state.Key] = newStatereachabilityStatus;
                    }
                    newStatereachabilityStatus.EvenReachable |= newReachability.EvenReachable;
                    newStatereachabilityStatus.OddReachable  |= newReachability.OddReachable;
                }
            }
            return(newReachabilityDictionary);
        }
예제 #2
0
 /// <summary>
 /// Updates a reachability status lookup by adding the data from the current reachabilityStatus
 /// </summary>
 private void UpdateReachabilityStatus(int fromState, ReachabilityStatus reachabilityStatus,
                                       Dictionary <int, ReachabilityStatus> reachabilityLookup, bool negated)
 {
     if (!reachabilityLookup.TryGetValue(fromState, out var currentReachabilityStatus))
     {
         currentReachabilityStatus     = new ReachabilityStatus();
         reachabilityLookup[fromState] = currentReachabilityStatus;
     }
     if (negated)
     {
         currentReachabilityStatus.EvenReachable |= reachabilityStatus.OddReachable;
         currentReachabilityStatus.OddReachable  |= reachabilityStatus.EvenReachable;
     }
     else
     {
         currentReachabilityStatus.EvenReachable |= reachabilityStatus.EvenReachable;
         currentReachabilityStatus.OddReachable  |= reachabilityStatus.OddReachable;
     }
 }
예제 #3
0
        internal static Automaton PopulateDFAWithXAndEpsilonTransitionsNaive(this Automaton automaton)
        {
            bool changes = true;

            while (changes)
            {
                changes = AddEpsilonStatesForXXSubPaths(automaton);
                // Look for paths (RRR/SS)
                foreach (var startState in automaton.States)
                {
                    // Now look for S * X^alpha * S states
                    var SSreachabilityDictionary = automaton.GetStatesReachableFromStateWithSymbol(startState, Constants.RegularLanguage.S,
                                                                                                   useEpsilonStatesFromInitial: false, useEpsilonStatesAtEnd: true)
                                                   .ToDictionary((s) => s, (s) => ReachabilityStatus.Even())
                                                   .ApplyXTransitionToReachabilityDictionary(automaton)
                                                   .ApplySOrRTransitionToReachabilityDictionary(automaton, Constants.RegularLanguage.S, false);
                    foreach (var(finalState, reachability) in SSreachabilityDictionary)
                    {
                        if (AddTransitionsFromReachabilityStatus(automaton, startState, finalState, reachability))
                        {
                            changes = true;
                        }
                    }
                    // Add R * X^alpha1 * R * X^alpha2 * R
                    var RRRreachabilityDictionary = automaton.GetStatesReachableFromStateWithSymbol(startState, Constants.RegularLanguage.R,
                                                                                                    useEpsilonStatesFromInitial: false, useEpsilonStatesAtEnd: true)
                                                    .ToDictionary((s) => s, (s) => ReachabilityStatus.Even())
                                                    .ApplyXTransitionToReachabilityDictionary(automaton)
                                                    .ApplySOrRTransitionToReachabilityDictionary(automaton, Constants.RegularLanguage.R, true)
                                                    .ApplyXTransitionToReachabilityDictionary(automaton)
                                                    .ApplySOrRTransitionToReachabilityDictionary(automaton, Constants.RegularLanguage.R, false);
                    foreach (var(finalState, reachability) in RRRreachabilityDictionary)
                    {
                        if (AddTransitionsFromReachabilityStatus(automaton, startState, finalState, reachability))
                        {
                            changes = true;
                        }
                    }
                }
            }
            return(automaton);
        }
예제 #4
0
        private static IReadOnlyDictionary <int, ReachabilityStatus> ApplySOrRTransitionToReachabilityDictionary(
            this IReadOnlyDictionary <int, ReachabilityStatus> currentReachabilityDictionary, Automaton automaton,
            char symbol, bool useEpsilonStatesAtEnd)
        {
            var newReachabilityDictionary = new Dictionary <int, ReachabilityStatus>();

            foreach (var(currentState, currentReachabilityStatus) in currentReachabilityDictionary)
            {
                var reachableStates = automaton.GetStatesReachableFromStateWithSymbol(currentState, symbol, false, useEpsilonStatesAtEnd);
                foreach (var state in reachableStates)
                {
                    if (!newReachabilityDictionary.TryGetValue(state, out var stateReachability))
                    {
                        stateReachability = new ReachabilityStatus();
                        newReachabilityDictionary[state] = stateReachability;
                    }
                    stateReachability.EvenReachable |= currentReachabilityStatus.EvenReachable;
                    stateReachability.OddReachable  |= currentReachabilityStatus.OddReachable;
                }
            }
            return(newReachabilityDictionary);
        }
예제 #5
0
        private static IReadOnlyDictionary <int, ReachabilityStatus> ApplyXTransitionToReachabilityDictionary(
            this IReadOnlyDictionary <int, ReachabilityStatus> currentReachabilityDictionary, Automaton automaton
            )
        {
            var newReachabilityDictionary = new Dictionary <int, ReachabilityStatus>(currentReachabilityDictionary);

            foreach (var(currentState, currentReachabilityStatus) in currentReachabilityDictionary)
            {
                var reachableStates = automaton.GetStatesReachableFromStateWithSymbol(currentState, Constants.RegularLanguage.X, false);
                // Now combine all those states with the current reachability dictionary
                foreach (var state in reachableStates)
                {
                    if (!newReachabilityDictionary.TryGetValue(state, out var stateReachability))
                    {
                        stateReachability = new ReachabilityStatus();
                        newReachabilityDictionary[state] = stateReachability;
                    }
                    // This state has reachability of the opposite of the previous state
                    stateReachability.OddReachable  |= currentReachabilityStatus.EvenReachable;
                    stateReachability.EvenReachable |= currentReachabilityStatus.OddReachable;
                }
            }
            return(newReachabilityDictionary);
        }
예제 #6
0
        private static bool AddTransitionsFromReachabilityStatus(Automaton automaton, int startState, int finalState, ReachabilityStatus reachabilityStatus)
        {
            bool changes = false;

            if (reachabilityStatus.EvenReachable)
            {
                if (automaton.AddTransition(startState, finalState, Constants.RegularLanguage.X))
                {
                    changes = true;
                }
            }
            else if (reachabilityStatus.OddReachable)
            {
                // Odd reachable so add X transition
                if (startState != finalState && automaton.AddTransition(startState, finalState, Automaton.Epsilon))
                {
                    changes = true;
                }
            }
            return(changes);
        }
예제 #7
0
        /// <summary>
        /// Adds a transition to the internally stored canonical state substrings. Returns a list of all transitions that should be added directly resulting from this
        /// </summary>
        public IReadOnlyCollection <Transition> AddTransition(int stateFrom, char symbol, int stateTo)
        {
            // This process works as follows:
            // - Check whether the transition already exists. If it already does, then just return.
            // - Add the transition to the lookup
            // - Calculate newly created transitions from the lookups

            var outTransitionLookup = _outgoingTransitionLookup[stateFrom].GetTransitionDictionary(symbol);
            var inTransitionLookup  = _incomingTransitionLookup[stateTo].GetTransitionDictionary(symbol);
            // Check whether the transition already exists, and add it if not.
            // We will check the outgoing transition from the stateFrom, but we expect it to be consistent between the outgoing and incoming transition
            // I.e. if s0 ----S----> s1, then we have S outgoing from s0 to s1, and S incoming on s1 from s0
            // Therefore, if something breaks here then we know that our code has produced an inconsistent state
            ReachabilityStatus fromReachabilityStatus;

            if (outTransitionLookup.TryGetValue(stateTo, out var toReachabilityStatus))
            {
                fromReachabilityStatus = inTransitionLookup[stateFrom];
            }
            else
            {
                toReachabilityStatus          = new ReachabilityStatus();
                outTransitionLookup[stateTo]  = toReachabilityStatus;
                fromReachabilityStatus        = new ReachabilityStatus();
                inTransitionLookup[stateFrom] = fromReachabilityStatus;
            }
            if (symbol != Constants.RegularLanguage.X)
            {
                if (toReachabilityStatus.EvenReachable)
                {
                    // Transition already exists
                    return(Array.Empty <Transition>());
                }
                else
                {
                    fromReachabilityStatus.EvenReachable = true;
                    toReachabilityStatus.EvenReachable   = true;
                }
            }
            else
            {
                if (toReachabilityStatus.OddReachable)
                {
                    // Transition already exists
                    return(Array.Empty <Transition>());
                }
                else
                {
                    toReachabilityStatus.OddReachable   = true;
                    fromReachabilityStatus.OddReachable = true;
                }
            }

            var toAddTransitions = new List <Transition>();

            Action <int, int, char> addTransition = (fromState, toState, symbol) =>
            {
                if (fromState == toState && symbol == Automaton.Epsilon)
                {
                    return;
                }
                if (!_automaton.AddTransition(fromState, toState, symbol))
                {
                    return;
                }
                toAddTransitions.Add(new Transition(fromState, toState, symbol));
            };

            // Adds an X or epsilon transition from a given state to another, based on an existing reachability status
            Action <int, int, ReachabilityStatus, bool> addTransitionFromReachabilityStatus = (fromState, toState, reachabilityStatus, negated) =>
            {
                if ((reachabilityStatus.EvenReachable && negated) || (reachabilityStatus.OddReachable && !negated))
                {
                    addTransition(fromState, toState, Constants.RegularLanguage.X);
                }
                if ((reachabilityStatus.OddReachable && negated) || (reachabilityStatus.EvenReachable && !negated))
                {
                    addTransition(fromState, toState, Automaton.Epsilon);
                }
            };

            Func <int, Dictionary <int, ReachabilityStatus> > getEpsilonReachabilityDictionary = (state) =>
            {
                var rightReachabilityDictionary       = _outgoingTransitionLookup[state].EpsilonTransitions.ToDictionary(kv => kv.Key, kv => kv.Value);
                ReachabilityStatus?reachabilityStatus = null;
                if (!rightReachabilityDictionary.TryGetValue(stateTo, out reachabilityStatus))
                {
                    reachabilityStatus = new ReachabilityStatus();
                    rightReachabilityDictionary[stateTo] = reachabilityStatus;
                }
                reachabilityStatus.EvenReachable |= true;
                return(rightReachabilityDictionary);
            };

            // Adds transitions for each side combined together with the middle. Should only be called on combinations that make sense.
            Action <Dictionary <int, ReachabilityStatus>, char, int, bool> combineWithBothSides =
                (incomingReachabilityLookup, symbol, rightSymbolCount, negated) =>
            {
                var rightReachabilityDictionary = getEpsilonReachabilityDictionary(stateTo);

                for (int i = 1; i <= rightSymbolCount; i++)
                {
                    rightReachabilityDictionary = ApplyTransitionToReachabilityDictionary(rightReachabilityDictionary, symbol, i != rightSymbolCount);
                }

                foreach (var leftReachabilityStatus in incomingReachabilityLookup)
                {
                    foreach (var rightReachabilityStatus in rightReachabilityDictionary)
                    {
                        var stateReachabilityStatus = leftReachabilityStatus.Value.Times(rightReachabilityStatus.Value);
                        addTransitionFromReachabilityStatus(leftReachabilityStatus.Key, rightReachabilityStatus.Key, stateReachabilityStatus, negated);
                    }
                }
            };

            Action <Dictionary <int, ReachabilityStatus>, bool> combineLeft =
                (incomingReachabilityLookup, negated) =>
            {
                foreach (var stateReachabilityLookup in incomingReachabilityLookup)
                {
                    addTransitionFromReachabilityStatus(stateReachabilityLookup.Key, stateTo, stateReachabilityLookup.Value, negated);
                }
            };

            Action <char, int, bool> combineRight =
                (symbol, rightSymbolCount, negated) =>
            {
                var rightReachabilityDictionary = getEpsilonReachabilityDictionary(stateTo);

                for (int i = 1; i <= rightSymbolCount; i++)
                {
                    rightReachabilityDictionary = ApplyTransitionToReachabilityDictionary(rightReachabilityDictionary, symbol, i != rightSymbolCount);
                }
                foreach (var rightReachabilityLookup in rightReachabilityDictionary)
                {
                    addTransitionFromReachabilityStatus(stateFrom, rightReachabilityLookup.Key, rightReachabilityLookup.Value, negated);
                }
            };

            // Update a given transition set, by iterating through all possibilities specified in the iterate lookup
            Action <int, Dictionary <int, ReachabilityStatus>, Func <StateTransitions, Dictionary <int, ReachabilityStatus> >, bool> updateTransitionSetEpsilon =
                (inState, iterateReachabilityLookup, getToReachabilitySet, negated) =>
            {
                foreach (var stateReachabilityLookup in iterateReachabilityLookup)
                {
                    var currentOutState           = stateReachabilityLookup.Key;
                    var currentReachabilityStatus = stateReachabilityLookup.Value;
                    UpdateReachabilityStatus(currentOutState, currentReachabilityStatus, getToReachabilitySet(_incomingTransitionLookup[inState]), negated);
                    UpdateReachabilityStatus(inState, currentReachabilityStatus, getToReachabilitySet(_outgoingTransitionLookup[currentOutState]), negated);
                }
            };

            Action <Dictionary <int, ReachabilityStatus>, Func <StateTransitions, Dictionary <int, ReachabilityStatus> >, bool> updateTransitionSetRight =
                (iterateReachabilityLookup, getToReachabilitySet, negated) =>
            {
                foreach (var stateReachabilityLookup in iterateReachabilityLookup)
                {
                    var currentReachabilityStatus = stateReachabilityLookup.Value;
                    UpdateReachabilityStatus(stateFrom, currentReachabilityStatus, getToReachabilitySet(_incomingTransitionLookup[stateReachabilityLookup.Key]), negated);
                    UpdateReachabilityStatus(stateReachabilityLookup.Key, currentReachabilityStatus, getToReachabilitySet(_outgoingTransitionLookup[stateFrom]), negated);
                }
            };

            Action <Dictionary <int, ReachabilityStatus>, Func <StateTransitions, Dictionary <int, ReachabilityStatus> >, bool> updateTransitionSetLeft =
                (iterateReachabilityLookup, getToReachabilitySet, negated) =>
            {
                foreach (var stateReachabilityLookup in iterateReachabilityLookup)
                {
                    foreach (var epsilonReachability in getEpsilonReachabilityDictionary(stateTo))
                    {
                        var combinedReachability = stateReachabilityLookup.Value.Times(epsilonReachability.Value);
                        UpdateReachabilityStatus(epsilonReachability.Key, combinedReachability, getToReachabilitySet(_outgoingTransitionLookup[stateReachabilityLookup.Key]), false);
                        UpdateReachabilityStatus(stateReachabilityLookup.Key, combinedReachability, getToReachabilitySet(_incomingTransitionLookup[epsilonReachability.Key]), false);
                    }
                }
            };

            Action <Dictionary <int, ReachabilityStatus>, Dictionary <int, ReachabilityStatus>, Func <StateTransitions, Dictionary <int, ReachabilityStatus> >, bool> updateTransitionSetBothSides =
                (leftIterateSet, rightIterateSet, getToReachabilitySet, negated) =>
            {
                foreach (var lefStateReachabilityLookup in leftIterateSet)
                {
                    foreach (var rightStateReachabilityLookup in rightIterateSet)
                    {
                        var leftState  = lefStateReachabilityLookup.Key;
                        var rightState = rightStateReachabilityLookup.Key;
                        var currentReachabilityStatus = lefStateReachabilityLookup.Value.Times(rightStateReachabilityLookup.Value);
                        UpdateReachabilityStatus(leftState, currentReachabilityStatus, getToReachabilitySet(_incomingTransitionLookup[rightState]), negated);
                        UpdateReachabilityStatus(rightState, currentReachabilityStatus, getToReachabilitySet(_outgoingTransitionLookup[leftState]), negated);
                    }
                }
            };

            // We have sk ---symbol--->  sj.
            // Now combine this with the incoming and outgoing transitions with sk and sjs
            switch (symbol)
            {
            // For S Combine with S transitions on each side (S + S = X)
            case Constants.RegularLanguage.S:
                updateTransitionSetRight(_outgoingTransitionLookup[stateTo].EpsilonTransitions, (s) => s.STransitions, false);
                // Combine new S transition with any incoming and outgoing S transitions
                combineRight('S', 1, true);
                combineLeft(_incomingTransitionLookup[stateFrom].STransitions, true);
                break;

            // For R Combine left with R and RR transitions on each side.(R + R = RR, RR + R = R + RR = X, R + R + R = X)
            // In other words:
            // For R + RR = X or RR + R = X  add a transition
            // For R + R + R = X add a transition
            // For R + R = RR update the dictionaries.
            case Constants.RegularLanguage.R:
                // Update R + X/epsilon
                updateTransitionSetRight(_outgoingTransitionLookup[stateTo].EpsilonTransitions, (s) => s.RTransitions, false);
                // Update R + R transitions either side
                updateTransitionSetLeft(_incomingTransitionLookup[stateFrom].RTransitions, (s) => s.RRTransitions, false);
                updateTransitionSetRight(_outgoingTransitionLookup[stateTo].RTransitions, (s) => s.RRTransitions, false);
                // Combine new R transition with any incoming RR transitions
                combineRight('R', 2, true);
                combineLeft(_incomingTransitionLookup[stateFrom].RRTransitions, true);
                // Update incoming and outgoing transitions for R + R + R
                combineWithBothSides(_incomingTransitionLookup[stateFrom].RTransitions, 'R', 1, true);
                // Combine new R transition with any incoming R transitions
                break;

            case Constants.RegularLanguage.X:
            case Automaton.Epsilon:
                // For X and Epsilon Combine with X, S, R and RR transitions on each side
                var even = true;
                if (symbol == Constants.RegularLanguage.X)
                {
                    // Update chains set
                    foreach (var chainEnd in _outgoingTransitionLookup[stateTo].EpsilonChains.Append(stateTo))
                    {
                        _outgoingTransitionLookup[stateFrom].XEpsilonChains.Add(chainEnd);
                        _incomingTransitionLookup[chainEnd].XEpsilonChains.Add(stateFrom);
                    }

                    even = false;
                    // Add epsilon transitions for X + X
                    // TODO: Potential optimisation:
                    // We shouldn't need to add the state to the queue here as the state should already be consistent at this point,
                    // so we should just add the state to the automaton, so long as it doesn't go to itself.
                    foreach (var xChainStart in _incomingTransitionLookup[stateFrom].XEpsilonChains)
                    {
                        addTransition(xChainStart, stateTo, Automaton.Epsilon);
                    }
                    var xStates = _automaton.GetStatesReachableFromStateWithSymbol(stateTo, 'X', true, false);
                    foreach (var xState in xStates)
                    {
                        addTransition(stateFrom, xState, Automaton.Epsilon);
                    }
                }
                else
                {
                    // Update chains set
                    _outgoingTransitionLookup[stateFrom].EpsilonChains.Add(stateTo);
                    _incomingTransitionLookup[stateTo].EpsilonChains.Add(stateFrom);
                    foreach (var chainEnd in _outgoingTransitionLookup[stateTo].EpsilonChains.Append(stateTo))
                    {
                        foreach (var chainStart in _incomingTransitionLookup[stateFrom].XEpsilonChains)
                        {
                            _outgoingTransitionLookup[chainStart].XEpsilonChains.Add(chainEnd);
                            _incomingTransitionLookup[chainEnd].XEpsilonChains.Add(chainStart);
                        }
                        foreach (var chainStart in _incomingTransitionLookup[stateFrom].EpsilonChains)
                        {
                            _outgoingTransitionLookup[chainStart].EpsilonChains.Add(chainEnd);
                            _incomingTransitionLookup[chainEnd].EpsilonChains.Add(chainStart);
                        }
                    }

                    // Combine with X on each side X
                    var incomingXEpsilonChains = _incomingTransitionLookup[stateFrom].XEpsilonChains;
                    var xStates = _automaton.GetStatesReachableFromStateWithSymbol(stateTo, 'X', true, false);

                    var newTransitions = new List <(int from, int to)>();
                    foreach (var startXState in incomingXEpsilonChains)
                    {
                        foreach (var outgoingX in xStates)
                        {
                            // Both X. Combine.
                            newTransitions.Add((startXState, outgoingX));
                        }
                    }
                    foreach (var transition in newTransitions)
                    {
                        addTransition(transition.from, transition.to, Automaton.Epsilon);
                    }
                }

                // First update the Transition lookup.
                // Update epsilon transitions
                updateTransitionSetRight(_outgoingTransitionLookup[stateTo].EpsilonTransitions, (s) => s.EpsilonTransitions, !even);
                // updateTransitionSetLeft(_incomingTransitionLookup[stateFrom].EpsilonTransitions, (s) => s.EpsilonTransitions, !even);
                updateTransitionSetEpsilon(stateTo, _incomingTransitionLookup[stateFrom].EpsilonTransitions, (s) => s.EpsilonTransitions, !even);
                // Combine with X,S,R,RR from front side. We only do the front side as the rules we are checking are XX, SXS, RXRXR.
                foreach (var reachabilityLookup in _outgoingTransitionLookup[stateFrom].EpsilonTransitions)
                {
                    if (reachabilityLookup.Value.EvenReachable)
                    {
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].STransitions, (s) => s.STransitions, false);
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].RTransitions, (s) => s.RTransitions, false);
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].RRTransitions, (s) => s.RRTransitions, false);
                    }
                    if (reachabilityLookup.Value.OddReachable)
                    {
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].STransitions, (s) => s.STransitions, true);
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].RTransitions, (s) => s.RTransitions, true);
                        updateTransitionSetEpsilon(reachabilityLookup.Key, _incomingTransitionLookup[stateFrom].RRTransitions, (s) => s.RRTransitions, true);
                    }
                }
                // Combine R + R
                var rightReachability = getEpsilonReachabilityDictionary(stateTo);
                rightReachability = ApplyTransitionToReachabilityDictionary(rightReachability, 'R', false);
                foreach (var incomingRReachability in _incomingTransitionLookup[stateFrom].RTransitions)
                {
                    foreach (var epsilonReachability in rightReachability)
                    {
                        var combinedReachability = incomingRReachability.Value.Times(epsilonReachability.Value);
                        UpdateReachabilityStatus(epsilonReachability.Key, combinedReachability, _outgoingTransitionLookup[incomingRReachability.Key].RRTransitions, !even);
                        UpdateReachabilityStatus(incomingRReachability.Key, combinedReachability, _incomingTransitionLookup[epsilonReachability.Key].RRTransitions, !even);
                    }
                }

                // Combine S + S
                combineWithBothSides(_incomingTransitionLookup[stateFrom].STransitions, 'S', 1, even);
                // Combine R + RR
                combineWithBothSides(_incomingTransitionLookup[stateFrom].RTransitions, 'R', 2, even);
                // Combine RR + R
                combineWithBothSides(_incomingTransitionLookup[stateFrom].RRTransitions, 'R', 1, even);

                break;

            default:
                throw new ArgumentException($"Character {symbol} has no understood implementation for canonicalisation");
            }
            return(toAddTransitions);
        }