org.eclipse.xtext.util.formallang.PdaUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.util.formallang.PdaUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.eclipse.xtext.util.formallang;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.util.formallang.NfaUtil.MappedComparator;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.Inject;

/**
 * @author Moritz Eysholdt - Initial contribution and API
 */
public class PdaUtil {

    public static class HashStack<T> implements Iterable<T> {

        protected LinkedList<T> list = Lists.newLinkedList();
        protected Set<T> set = Sets.newLinkedHashSet();

        public boolean contains(Object value) {
            return set.contains(value);
        }

        public boolean isEmpty() {
            return list.isEmpty();
        }

        @Override
        public Iterator<T> iterator() {
            return list.iterator();
        }

        public T peek() {
            return list.getLast();
        }

        public T pop() {
            T result = list.getLast();
            list.removeLast();
            set.remove(result);
            return result;
        }

        public boolean push(T value) {
            boolean result = set.add(value);
            if (result)
                list.addLast(value);
            return result;
        }

        @Override
        public String toString() {
            return list.toString();
        }
    }

    protected static class IsPop<S, P> implements Predicate<S> {
        private final Pda<S, P> pda;

        private IsPop(Pda<S, P> pda) {
            this.pda = pda;
        }

        @Override
        public boolean apply(S input) {
            return pda.getPop(input) != null;
        }
    }

    public static class CyclicStackItem<T> {
        protected CyclicStackItem<T> parent;
        protected T item;

        public CyclicStackItem() {
            this.parent = null;
        }

        public CyclicStackItem(CyclicStackItem<T> parent, T item) {
            super();
            this.parent = parent;
            this.item = item;
        }

        public CyclicStackItem<T> push(T item) {
            int count = 0;
            CyclicStackItem<T> current = this;
            while (current != null) {
                if (current.item == item)
                    count++;
                current = current.parent;
            }
            if (count >= 2)
                return null;
            return new CyclicStackItem<T>(this, item);
        }

        public CyclicStackItem<T> pop(T item) {
            if (parent == null || this.item != item)
                return null;
            return parent;
        }
    }

    public static class CyclicStackTraverser<S, P> implements Traverser<Pda<S, P>, S, CyclicStackItem<P>> {
        @Override
        public CyclicStackItem<P> enter(Pda<S, P> pda, S state, CyclicStackItem<P> previous) {
            P item;
            if ((item = pda.getPush(state)) != null)
                return previous.push(item);
            if ((item = pda.getPop(state)) != null)
                return previous.pop(item);
            if (previous == null)
                return new CyclicStackItem<P>();
            return previous;
        }

        @Override
        public boolean isSolution(CyclicStackItem<P> result) {
            return result.parent == null;
        }
    }

    protected class StackItem<T> {
        protected StackItem<T> parent;
        protected T value;

        public StackItem(StackItem<T> parent, T value) {
            super();
            this.parent = parent;
            this.value = value;
        }

        public T peek() {
            return value;
        }

        public StackItem<T> pop() {
            if (parent != null)
                return parent;
            return null;
        }

        public StackItem<T> push(T value) {
            return new StackItem<T>(this, value);
        }

        public int size() {
            int result = 0;
            StackItem<T> current = this;
            while (current != null) {
                result++;
                current = current.pop();
            }
            return result;
        }

        @Override
        public String toString() {
            List<String> result = Lists.newArrayList();
            StackItem<T> current = this;
            while (current != null) {
                if (current.value != null)
                    result.add(current.value.toString());
                current = current.pop();
            }
            return Joiner.on(", ").join(result);
        }
    }

    protected class TraceItem<S, P> {
        protected TraceItem<S, P> parent;
        protected StackItem<P> stackitem;
        protected S state;

        public TraceItem(TraceItem<S, P> parent, S state, StackItem<P> stackitem) {
            super();
            this.parent = parent;
            this.state = state;
            this.stackitem = stackitem;
        }

        public List<S> asList() {
            List<S> result = Lists.newArrayList();
            TraceItem<S, P> current = this;
            while (current != null) {
                result.add(current.state);
                current = current.parent;
            }
            Collections.reverse(result);
            return result;
        }

        public int size() {
            int result = 0;
            TraceItem<S, P> current = this;
            while (current != null) {
                result++;
                current = current.parent;
            }
            return result;
        }

        @Override
        public String toString() {
            return "States: " + asList() + " Stack: " + stackitem;
        }

    }

    protected static class TraversalItem<S, R> {
        protected R data;
        protected Iterator<S> followers;
        protected S state;

        public TraversalItem(S state, Iterable<S> followers, R previous) {
            super();
            this.state = state;
            this.followers = followers.iterator();
            this.data = previous;
        }

        @Override
        @SuppressWarnings("rawtypes")
        public boolean equals(Object obj) {
            if (obj == null || obj.getClass() != getClass())
                return false;
            TraversalItem other = (TraversalItem) obj;
            return data.equals(other.data) && state.equals(other.state);
        }

        @Override
        public int hashCode() {
            return data.hashCode() + (state.hashCode() * 7);
        }

        @Override
        public String toString() {
            return state.toString();
        }
    }

    @Inject
    protected NfaUtil nfaUtil = new NfaUtil();

    public final long UNREACHABLE = Long.MAX_VALUE;

    public <S, P> boolean canReach(Pda<S, P> pda, S state, Iterator<P> stack, Predicate<S> matches,
            Predicate<S> canPass) {
        return distanceTo(pda, Collections.singleton(state), stack, matches, canPass) != UNREACHABLE;
    }

    protected static class Identity<T> {
        protected Map<T, T> cache = Maps.newHashMap();

        public T get(T t) {
            T r = cache.get(t);
            if (r != null)
                return r;
            cache.put(t, t);
            return t;
        }
    }

    public <S, P, T, D extends Pda<S, P>> D expand(Pda<S, P> pda, Function<S, Pda<S, P>> expand,
            Function<S, T> tokens, PdaFactory<D, S, P, T> fact) {
        D result = fact.create(tokens.apply(pda.getStart()), tokens.apply(pda.getStop()));
        Identity<S> identity = new Identity<S>();
        Map<S, S> idstates = Maps.newIdentityHashMap();
        Multimap<S, S> followers = LinkedHashMultimap.create();
        for (S s_old : nfaUtil.collect(pda)) {
            S s_new = idstates.get(s_old);
            if (s_new == null) {
                Pda<S, P> sub = expand.apply(s_old);
                if (sub != null) {
                    S s_start = identity.get(fact.createPush(result, tokens.apply(s_old)));
                    S s_stop = identity.get(fact.createPop(result, tokens.apply(s_old)));
                    idstates.put(s_old, s_start);
                    idstates.put(sub.getStart(), s_start);
                    idstates.put(sub.getStop(), s_stop);
                    followers.putAll(s_start, sub.getFollowers(sub.getStart()));
                    followers.putAll(s_stop, pda.getFollowers(s_old));
                    for (S f_old : nfaUtil.collect(sub))
                        if (f_old != sub.getStart() && f_old != sub.getStop()) {
                            S f_new = idstates.get(f_old);
                            if (f_new == null) {
                                idstates.put(f_old, f_new = clone(f_old, sub, result, tokens, fact, identity));
                                followers.putAll(f_new, pda.getFollowers(f_old));
                            }
                        }
                } else {
                    idstates.put(s_old, s_new = clone(s_old, pda, result, tokens, fact, identity));
                    followers.putAll(s_new, pda.getFollowers(s_old));
                }
            }
        }
        for (Map.Entry<S, Collection<S>> entry : followers.asMap().entrySet()) {
            Set<S> f = Sets.newLinkedHashSet();
            for (S s : entry.getValue())
                f.add(idstates.get(s));
            fact.setFollowers(result, entry.getKey(), f);
        }
        return result;
    }

    protected <S, P, T, D extends Pda<S, P>> S clone(S state, Pda<S, P> src, D target, Function<S, T> tokens,
            PdaFactory<D, S, P, T> fact, Identity<S> identity) {
        if (state == src.getStart())
            return target.getStart();
        if (state == src.getStop())
            return target.getStop();
        P push = src.getPush(state);
        if (push != null)
            return identity.get(fact.createPush(target, tokens.apply(state)));
        P pop = src.getPop(state);
        if (pop != null)
            return identity.get(fact.createPop(target, tokens.apply(state)));
        return identity.get(fact.createState(target, tokens.apply(state)));
    }

    public <S, P, E, T, D extends Pda<S, P>> D create(Cfg<E, T> cfg, FollowerFunction<E> ff,
            PdaFactory<D, S, P, ? super E> fact) {
        return create(cfg, ff, Functions.<E>identity(), fact);
    }

    protected <S, P, E, T1, T2, D extends Pda<S, P>> void create(Cfg<E, T1> cfg, D pda, S state, E ele,
            Iterable<E> followerElements, FollowerFunction<E> ff, Function<E, T2> tokens,
            PdaFactory<D, S, P, ? super T2> fact, Map<E, S> states, Map<E, S> stops, Multimap<E, E> callers) {
        List<S> followerStates = Lists.newArrayList();
        for (E fol : followerElements) {
            E e;
            if (fol == null) {
                E root = new ProductionUtil().getRoot(cfg, ele);
                if (root == cfg.getRoot())
                    followerStates.add(pda.getStop());
                for (E c : callers.get(root)) {
                    S s = stops.get(c);
                    if (s == null) {
                        s = fact.createPop(pda, tokens.apply(c));
                        stops.put(c, s);
                        create(cfg, pda, s, c, ff.getFollowers(c), ff, tokens, fact, states, stops, callers);
                    }
                    followerStates.add(s);
                }
            } else if ((e = cfg.getCall(fol)) != null) {
                S s = states.get(fol);
                if (s == null) {
                    s = fact.createPush(pda, tokens.apply(fol));
                    states.put(fol, s);
                    create(cfg, pda, s, e, ff.getStarts(e), ff, tokens, fact, states, stops, callers);
                }
                followerStates.add(s);
            } else {
                S s = states.get(fol);
                if (s == null) {
                    s = fact.createState(pda, tokens.apply(fol));
                    states.put(fol, s);
                    create(cfg, pda, s, fol, ff.getFollowers(fol), ff, tokens, fact, states, stops, callers);
                }
                followerStates.add(s);
            }
        }
        fact.setFollowers(pda, state, followerStates);
    }

    public <S, P, E, T1, T2, D extends Pda<S, P>> D create(Cfg<E, T1> cfg, FollowerFunction<E> ff,
            Function<E, T2> element2token, PdaFactory<D, S, P, ? super T2> fact) {
        D pda = fact.create(null, null);
        Map<E, S> states = Maps.newLinkedHashMap();
        Map<E, S> stops = Maps.newLinkedHashMap();
        Multimap<E, E> callers = new CfgUtil().getCallers(cfg);
        create(cfg, pda, pda.getStart(), cfg.getRoot(), ff.getStarts(cfg.getRoot()), ff, element2token, fact,
                states, stops, callers);
        return pda;
    }

    protected <T> StackItem<T> createStack(Iterator<T> stack) {
        StackItem<T> result = new StackItem<T>((StackItem<T>) null, null);
        ArrayList<T> list = Lists.newArrayList(stack);
        for (int i = list.size() - 1; i >= 0; i--)
            result = new StackItem<T>(result, list.get(i));
        return result;
    }

    public <S, P> long distanceTo(Pda<S, P> pda, Iterable<S> starts, Iterator<P> stack, Predicate<S> matches,
            Predicate<S> canPass) {
        TraceItem<S, P> trace = trace(pda, starts, stack, matches, canPass);
        if (trace != null)
            return trace.size();
        return UNREACHABLE;
    }

    public <S, P, R, D extends Pda<S, P>> D filterEdges(Pda<S, P> pda, Traverser<? super Pda<S, P>, S, R> traverser,
            PdaFactory<D, S, P, S> factory) {
        Map<S, Integer> distances = new NfaUtil().distanceToFinalStateMap(pda);
        return filterEdges(pda, traverser, distances, factory);
    }

    public <S, P, R, D extends Pda<S, P>> D filterEdges(Pda<S, P> pda, Traverser<? super Pda<S, P>, S, R> traverser,
            Map<S, Integer> distances, PdaFactory<D, S, P, S> factory) {
        HashStack<TraversalItem<S, R>> trace = new HashStack<TraversalItem<S, R>>();
        R previous = traverser.enter(pda, pda.getStart(), null);
        if (previous == null)
            return factory == null ? null : factory.create(pda.getStart(), pda.getStop());
        MappedComparator<S, Integer> distanceComp = new MappedComparator<S, Integer>(distances);
        trace.push(newItem(pda, distanceComp, distances, pda.getStart(), previous));
        Multimap<S, S> edges = LinkedHashMultimap.create();
        HashSet<S> states = Sets.newLinkedHashSet();
        HashSet<Pair<S, R>> success = Sets.newLinkedHashSet();
        states.add(pda.getStart());
        states.add(pda.getStop());
        ROOT: while (!trace.isEmpty()) {
            TraversalItem<S, R> current = trace.peek();
            while (current.followers.hasNext()) {
                S next = current.followers.next();
                R item = traverser.enter(pda, next, current.data);
                if (item != null) {
                    if ((next == pda.getStop() && traverser.isSolution(item))
                            || success.contains(Tuples.create(next, item))) {
                        S s = null;
                        for (TraversalItem<S, R> i : trace) {
                            if (s != null)
                                edges.put(s, i.state);
                            states.add(i.state);
                            success.add(Tuples.create(i.state, i.data));
                            s = i.state;
                        }
                        edges.put(s, next);
                    } else {
                        if (trace.push(newItem(pda, distanceComp, distances, next, item)))
                            continue ROOT;
                    }
                }
            }
            trace.pop();
        }
        if (factory == null)
            return null;
        D result = factory.create(pda.getStart(), pda.getStop());
        Map<S, S> old2new = Maps.newLinkedHashMap();
        old2new.put(pda.getStart(), result.getStart());
        old2new.put(pda.getStop(), result.getStop());
        for (S old : states) {
            if (old == pda.getStart() || old == pda.getStop())
                continue;
            else if (pda.getPop(old) != null)
                old2new.put(old, factory.createPop(result, old));
            else if (pda.getPush(old) != null)
                old2new.put(old, factory.createPush(result, old));
            else
                old2new.put(old, factory.createState(result, old));
        }
        for (S old : states) {
            List<S> followers = Lists.newArrayList();
            for (S f : edges.get(old))
                followers.add(old2new.get(f));
            factory.setFollowers(result, old2new.get(old), followers);
        }
        return result;
    }

    public <S, P> Nfa<S> filterUnambiguousPaths(Pda<S, P> pda) {
        Map<S, List<S>> followers = Maps.newLinkedHashMap();
        Map<S, Integer> distanceMap = nfaUtil.distanceToFinalStateMap(pda);
        filterUnambiguousPaths(pda, pda.getStart(), distanceMap, followers);
        return new NfaUtil.NFAImpl<S>(pda.getStart(), pda.getStop(), followers);
    }

    protected <S, P> void filterUnambiguousPaths(final Pda<S, P> pda, S state, Map<S, Integer> dist,
            Map<S, List<S>> followers) {
        if (followers.containsKey(state))
            return;
        List<S> f = Lists.newArrayList(pda.getFollowers(state));
        if (f.size() <= 1) {
            followers.put(state, f);
            if (f.size() == 1)
                filterUnambiguousPaths(pda, f.get(0), dist, followers);
            return;
        }
        int closestDist = dist.get(f.get(0));
        S closest = f.get(0);
        for (int i = 1; i < f.size(); i++) {
            int d = dist.get(f.get(i));
            if (d < closestDist) {
                closestDist = d;
                closest = f.get(i);
            }
        }
        IsPop<S, P> isPop = new IsPop<S, P>(pda);
        Set<S> closestPops = nfaUtil.findFirst(pda, Collections.singleton(closest), isPop);
        Iterator<S> it = f.iterator();
        while (it.hasNext()) {
            S next = it.next();
            if (next != closest) {
                Set<S> nextPops = nfaUtil.findFirst(pda, Collections.singleton(next), isPop);
                if (!closestPops.equals(nextPops))
                    it.remove();
            }
        }
        followers.put(state, f);
        for (S follower : f)
            filterUnambiguousPaths(pda, follower, dist, followers);
    }

    protected <S, R, P> TraversalItem<S, R> newItem(Pda<S, P> pda, MappedComparator<S, Integer> comp,
            Map<S, Integer> distances, S next, R item) {
        List<S> followers = Lists.newArrayList();
        for (S f : pda.getFollowers(next))
            if (distances.containsKey(f))
                followers.add(f);
        Collections.sort(followers, comp);
        return new TraversalItem<S, R>(next, followers, item);
    }

    public <S, P> List<S> shortestPathTo(Pda<S, P> pda, Iterable<S> starts, Iterator<P> stack, Predicate<S> matches,
            Predicate<S> canPass) {
        TraceItem<S, P> trace = trace(pda, starts, stack, matches, canPass);
        if (trace != null)
            return trace.asList();
        return null;
    }

    public <S, P> List<S> shortestPathTo(Pda<S, P> pda, Iterator<P> stack, Predicate<S> matches) {
        return shortestPathTo(pda, pda.getStart(), stack, matches, Predicates.<S>alwaysTrue());
    }

    public <S, P> List<S> shortestPathTo(Pda<S, P> pda, Iterator<P> stack, Predicate<S> matches,
            Predicate<S> canPass) {
        return shortestPathTo(pda, pda.getStart(), stack, matches, canPass);
    }

    public <S, P> List<S> shortestPathTo(Pda<S, P> pda, Iterator<P> stack, S match) {
        return shortestPathTo(pda, pda.getStart(), stack, Predicates.equalTo(match), Predicates.<S>alwaysTrue());
    }

    public <S, P> List<S> shortestPathTo(Pda<S, P> pda, S start, Iterator<P> stack, Predicate<S> matches,
            Predicate<S> canPass) {
        TraceItem<S, P> trace = trace(pda, Collections.singleton(start), stack, matches, canPass);
        if (trace != null)
            return trace.asList();
        return null;
    }

    public <S, P> List<S> shortestPathToFinalState(Pda<S, P> pda, Iterator<P> stack) {
        return shortestPathTo(pda, pda.getStart(), stack, Predicates.equalTo(pda.getStop()),
                Predicates.<S>alwaysTrue());
    }

    public <S, P> List<S> shortestStackpruningPathTo(Pda<S, P> pda, Iterable<S> starts, Iterator<P> stack,
            Predicate<S> matches, Predicate<S> canPass) {
        TraceItem<S, P> trace = traceToWithPruningStack(pda, starts, stack, matches, canPass);
        if (trace != null)
            return trace.asList();
        return null;
    }

    public <S, P> List<S> shortestStackpruningPathTo(Pda<S, P> pda, Iterator<P> stack, Predicate<S> matches) {
        return shortestStackpruningPathTo(pda, pda.getStart(), stack, matches, Predicates.<S>alwaysTrue());
    }

    public <S, P> List<S> shortestStackpruningPathTo(Pda<S, P> pda, Iterator<P> stack, S matches) {
        return shortestStackpruningPathTo(pda, pda.getStart(), stack, Predicates.equalTo(matches),
                Predicates.<S>alwaysTrue());
    }

    public <S, P> List<S> shortestStackpruningPathTo(Pda<S, P> pda, S start, Iterator<P> stack,
            Predicate<S> matches, Predicate<S> canPass) {
        TraceItem<S, P> trace = traceToWithPruningStack(pda, Collections.singleton(start), stack, matches, canPass);
        if (trace != null)
            return trace.asList();
        return null;
    }

    public <S, P, R> List<R> collectReachable(Pda<S, P> pda, final Function<S, R> function) {
        final List<R> result = Lists.newArrayList();
        Iterator<P> stack = Collections.<P>emptyList().iterator();
        Predicate<S> matches = Predicates.<S>alwaysFalse();
        Predicate<S> canPass = new Predicate<S>() {
            @Override
            public boolean apply(S input) {
                R r = function.apply(input);
                if (r != null) {
                    result.add(r);
                    return false;
                } else {
                    return true;
                }
            }
        };
        trace(pda, Collections.singleton(pda.getStart()), stack, matches, canPass);
        return result;
    }

    protected <S, P> TraceItem<S, P> trace(Pda<S, P> pda, Iterable<S> starts, Iterator<P> stack,
            Predicate<S> matches, Predicate<S> canPass) {
        StackItem<P> stackItem = createStack(stack);
        List<TraceItem<S, P>> current = Lists.newArrayList();
        Set<S> visited = Sets.newLinkedHashSet(starts);
        for (S start : starts) {
            //         if (matches.apply(start))
            //            return new TraceItem<S, P>(null, start, stackItem);
            current.add(new TraceItem<S, P>(null, start, stackItem));
        }
        int counter = stackItem.size() * -1;
        while (current.size() > 0 && counter < visited.size()) {
            List<TraceItem<S, P>> newCurrent = Lists.newArrayList();
            for (TraceItem<S, P> trace : current)
                for (S follower : pda.getFollowers(trace.state)) {
                    if (matches.apply(follower))
                        return new TraceItem<S, P>(trace, follower, trace.stackitem);
                    if (canPass.apply(follower)) {
                        P push = pda.getPush(follower);
                        visited.add(follower);
                        if (push != null) {
                            StackItem<P> pushed = trace.stackitem.push(push);
                            newCurrent.add(new TraceItem<S, P>(trace, follower, pushed));
                        } else {
                            P pop = pda.getPop(follower);
                            if (pop != null) {
                                if (trace.stackitem != null && pop == trace.stackitem.peek()) {
                                    StackItem<P> popped = trace.stackitem.pop();
                                    newCurrent.add(new TraceItem<S, P>(trace, follower, popped));
                                }
                            } else
                                newCurrent.add(new TraceItem<S, P>(trace, follower, trace.stackitem));
                        }
                    }
                }
            current = newCurrent;
            counter++;
        }
        return null;
    }

    protected <S, P> TraceItem<S, P> traceToWithPruningStack(Pda<S, P> pda, Iterable<S> starts, Iterator<P> stack,
            Predicate<S> matches, Predicate<S> canPass) {
        StackItem<P> stackItem = createStack(stack);
        List<TraceItem<S, P>> current = Lists.newArrayList();
        Set<S> visited = Sets.newLinkedHashSet(starts);
        TraceItem<S, P> result = null;
        for (S start : starts) {
            TraceItem<S, P> item = new TraceItem<S, P>(null, start, stackItem);
            //         if (matches.apply(start))
            //            result = item;
            current.add(item);
        }
        int counter = stackItem.size() * -1;
        while (current.size() > 0 && counter < visited.size()) {
            List<TraceItem<S, P>> newCurrent = Lists.newArrayList();
            for (TraceItem<S, P> trace : current)
                for (S follower : pda.getFollowers(trace.state)) {
                    if (matches.apply(follower)) {
                        TraceItem<S, P> found = new TraceItem<S, P>(trace, follower, trace.stackitem);
                        if (found.stackitem == null)
                            return found;
                        if (result == null || result.stackitem.size() > found.stackitem.size()) {
                            result = found;
                            counter = result.stackitem.size() * -1;
                        } else if (result.stackitem.size() == found.stackitem.size()
                                && result.size() > found.size()) {
                            result = found;
                            counter = result.stackitem.size() * -1;
                        }
                    }
                    if (canPass.apply(follower)) {
                        P push = pda.getPush(follower);
                        visited.add(follower);
                        if (push != null) {
                            StackItem<P> pushed = trace.stackitem.push(push);
                            newCurrent.add(new TraceItem<S, P>(trace, follower, pushed));
                        } else {
                            P pop = pda.getPop(follower);
                            if (pop != null) {
                                if (trace.stackitem != null && pop == trace.stackitem.peek()) {
                                    StackItem<P> popped = trace.stackitem.pop();
                                    newCurrent.add(new TraceItem<S, P>(trace, follower, popped));
                                }
                            } else
                                newCurrent.add(new TraceItem<S, P>(trace, follower, trace.stackitem));
                        }
                    }
                }
            current = newCurrent;
            counter++;
        }
        return result;
    }

    public <S, P, D extends Pda<S, P>> D filterOrphans(Pda<S, P> pda, PdaFactory<D, S, P, S> factory) {
        CyclicStackTraverser<S, P> traverser = new CyclicStackTraverser<S, P>();
        return filterEdges(pda, traverser, factory);
    }

    public <S, P, D extends Pda<S, P>> Map<P, Pair<S, S>> collectPopsAndPushs(Pda<S, P> pda) {
        Map<P, Pair<S, S>> result = Maps.newLinkedHashMap();
        for (S s : nfaUtil.collect(pda)) {
            P push = pda.getPush(s);
            if (push != null) {
                Pair<S, S> o = result.get(push);
                Pair<S, S> n = Tuples.create(s, o == null ? null : o.getSecond());
                result.put(push, n);
            }
            P pop = pda.getPop(s);
            if (pop != null) {
                Pair<S, S> o = result.get(pop);
                Pair<S, S> n = Tuples.create(o == null ? null : o.getFirst(), s);
                result.put(pop, n);
            }
        }
        return result;
    }

    public <S, P, D extends Pda<S, P>> Map<S, S> mapPopAndPush(Pda<S, P> pda) {
        Map<P, Pair<S, S>> popsAndPushs = collectPopsAndPushs(pda);
        Map<S, S> result = Maps.newLinkedHashMap();
        for (Pair<S, S> p : popsAndPushs.values()) {
            S push = p.getFirst();
            S pop = p.getSecond();
            if (push != null && pop != null) {
                result.put(push, pop);
                result.put(pop, push);
            }
        }
        return result;
    }

    public <S, P, D extends Pda<S, P>> D filter(Pda<S, P> pda, Predicate<S> filter,
            PdaFactory<D, S, P, ? super S> fact) {
        D result = fact.create(pda.getStart(), pda.getStop());
        Map<S, S> orig2copy = Maps.newLinkedHashMap();
        S start = pda.getStart();
        S stop = pda.getStop();
        orig2copy.put(start, result.getStart());
        orig2copy.put(stop, result.getStop());
        for (S orig : new NfaUtil().collect(pda)) {
            if (orig != start && orig != stop && filter.apply(orig)) {
                if (pda.getPop(orig) != null) {
                    orig2copy.put(orig, fact.createPop(result, orig));
                } else if (pda.getPush(orig) != null) {
                    orig2copy.put(orig, fact.createPush(result, orig));
                } else {
                    orig2copy.put(orig, fact.createState(result, orig));
                }
            }
        }
        for (Map.Entry<S, S> e : orig2copy.entrySet()) {
            S orig = e.getKey();
            S copy = e.getValue();
            LinkedList<S> todo = Lists.newLinkedList();
            todo.add(orig);
            Set<S> visited = Sets.newHashSet();
            Set<S> folowers = Sets.newHashSet();
            while (!todo.isEmpty()) {
                S o = todo.pop();
                if (visited.add(o)) {
                    for (S s : pda.getFollowers(o)) {
                        S f = orig2copy.get(s);
                        if (f != null) {
                            folowers.add(f);
                        } else {
                            todo.add(s);
                        }
                    }
                }
            }
            fact.setFollowers(result, copy, folowers);
        }
        return result;
    }

}