Package dk.brics.string.mlfa.operations

Source Code of dk.brics.string.mlfa.operations.MLFA2Automaton

package dk.brics.string.mlfa.operations;

import dk.brics.automaton.Automaton;
import dk.brics.automaton.State;
import dk.brics.automaton.StatePair;
import dk.brics.string.mlfa.*;

import java.util.*;

/**
* Converter from MLFAs to automata.
*
* @see dk.brics.string.StringAnalysis
*/
public class MLFA2Automaton {

    private Map<MLFAStatePair, Automaton> memo;

    private List<Set<MLFAState>> succs, prevs;

    private List<Set<MLFAState>> forward_reachable, backward_reachable;

    /**
     * Construcs a new converter for the given MLFA.
     */
    public MLFA2Automaton(MLFA m) {
        memo = new HashMap<MLFAStatePair, Automaton>();
        succs = new ArrayList<Set<MLFAState>>();
        prevs = new ArrayList<Set<MLFAState>>();
        forward_reachable = new ArrayList<Set<MLFAState>>();
        backward_reachable = new ArrayList<Set<MLFAState>>();
        for (int i = 0; i < m.getNumberOfStates(); i++) {
            succs.add(new HashSet<MLFAState>());
            prevs.add(new HashSet<MLFAState>());
            forward_reachable.add(null);
            backward_reachable.add(null);
        }
        for (MLFAState s : m.getStates()) {
            for (MLFAEdge e : s.getEdges()) {
                MLFAState d = e.getDestination();
                succs.get(s.getKey()).add(d);
                prevs.get(d.getKey()).add(s);
            }
        }
    }

    /**
     * Extracts ordinary minimal deterministic finite automaton from the MLFA.
     *
     * @param p pair representing initial and final state
     * @return minimal deterministic finite automaton (should not be modified by caller)
     */
    public Automaton extract(MLFAStatePair p) {
        return extract(p.getFirstState(), p.getSecondState(), new HashSet<MLFAStatePair>());
    }

    private Automaton extract(MLFAState s, MLFAState f, final Set<MLFAStatePair> stack) {
        MLFAStatePair p = new MLFAStatePair(s, f);
        Automaton a = memo.get(p);
        if (a != null) {
            return a;
        }
        if (stack.contains(p)) {
            throw new RuntimeException("MLFA is non-rankable");
        }
        stack.add(p);
        Set<MLFAState> reachable = findReachable(s, f);

        // handle special case with just one automaton/epsilon/identity transition from s to f
        if (((s != f && reachable.size() == 2) || (s == f && reachable.size() == 1))
                && s.getEdges().size() == 1 && f.getEdges().size() == 0) {
            MLFATransition t = s.getEdges().iterator().next().getTransition();
            a = t.visitBy(new TransitionVisitor<Automaton>() {

                public Automaton visitAutomatonTransition(AutomatonTransition t) {
                    return t.getAutomaton();
                }

                public Automaton visitEpsilonTransition(EpsilonTransition t) {
                    return Automaton.makeEmptyString();
                }

                public Automaton visitIdentityTransition(IdentityTransition t) {
                    return extract(t.getStartState(), t.getFinalState(), stack);
                }

                public Automaton visitUnaryTransition(UnaryTransition t) {
                    return null;
                }

                public Automaton visitBinaryTransition(BinaryTransition t) {
                    return null;
                }
            });
        }
        if (a == null) {
            a = new Automaton();

            // construct automaton states
            Map<MLFAState, State> statemap = new HashMap<MLFAState, State>();
            for (MLFAState q : reachable) {
                State ss = new State();
                statemap.put(q, ss);
                if (q == s) {
                    a.setInitialState(ss);
                }
                if (q == f) {
                    ss.setAccept(true);
                }
            }

            // add transitions
            final Set<StatePair> epsilons = new HashSet<StatePair>();
            for (MLFAState q : reachable) {
                for (MLFAEdge e : q.getEdges()) {
                    if (reachable.contains(e.getDestination())) {
                        final State qq = statemap.get(q);
                        final State pp = statemap.get(e.getDestination());
                        Automaton b = e.getTransition().visitBy(new TransitionVisitor<Automaton>() {

                            public Automaton visitAutomatonTransition(AutomatonTransition t) {
                                return t.getAutomaton().clone();
                            }

                            public Automaton visitEpsilonTransition(EpsilonTransition t) {
                                epsilons.add(new StatePair(qq, pp));
                                return null;
                            }

                            public Automaton visitIdentityTransition(IdentityTransition t) {
                                return extract(t.getStartState(), t.getFinalState(), stack).clone();
                            }

                            public Automaton visitUnaryTransition(UnaryTransition t) {
                                return t.getOperation().op(extract(t.getStartState(), t.getFinalState(), stack));
                            }

                            public Automaton visitBinaryTransition(BinaryTransition t) {
                                return t.getOperation().op(
                                        extract(t.getStartState1(), t.getFinalState1(), stack),
                                        extract(t.getStartState2(), t.getFinalState2(), stack));
                            }
                        });
                        if (b != null) {
                            epsilons.add(new StatePair(qq, b.getInitialState()));
                            for (State rr : b.getAcceptStates()) {
                                rr.setAccept(false);
                                epsilons.add(new StatePair(rr, pp));
                            }
                        }
                    }
                }
            }
            a.addEpsilons(epsilons);
            a.minimize();
        }
        stack.remove(p);
        memo.put(p, a);
        return a;
    }

    private Set<MLFAState> getForwardReachable(MLFAState s) { // TODO: improve performance of getXXReachable using strongly connected components?
        Set<MLFAState> reachable = forward_reachable.get(s.getKey());
        if (reachable == null) {
            reachable = new HashSet<MLFAState>();
            Set<MLFAState> pending = new HashSet<MLFAState>();
            pending.add(s);
            while (!pending.isEmpty()) {
                MLFAState p = pending.iterator().next();
                pending.remove(p);
                reachable.add(p);
                for (MLFAState q : succs.get(p.getKey())) {
                    if (!reachable.contains(q)) {
                        pending.add(q);
                    }
                }
            }
            forward_reachable.set(s.getKey(), reachable);
        }
        return reachable;
    }

    private Set<MLFAState> getBackwardReachable(MLFAState s) {
        Set<MLFAState> reachable = backward_reachable.get(s.getKey());
        if (reachable == null) {
            reachable = new HashSet<MLFAState>();
            Set<MLFAState> pending = new HashSet<MLFAState>();
            pending.add(s);
            while (!pending.isEmpty()) {
                MLFAState p = pending.iterator().next();
                pending.remove(p);
                reachable.add(p);
                for (MLFAState q : prevs.get(p.getKey())) {
                    if (!reachable.contains(q)) {
                        pending.add(q);
                    }
                }
            }
            backward_reachable.set(s.getKey(), reachable);
        }
        return reachable;
    }

    /**
     * Finds states that are reachable from p and can reach f.
     */
    private Set<MLFAState> findReachable(MLFAState p, MLFAState f) {
        Set<MLFAState> r = new HashSet<MLFAState>(getForwardReachable(p));
        r.retainAll(getBackwardReachable(f));
        return r;
    }
}
TOP

Related Classes of dk.brics.string.mlfa.operations.MLFA2Automaton

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.