Package solver.constraints.nary.automata.FA

Source Code of solver.constraints.nary.automata.FA.FiniteAutomaton

/**
*  Copyright (c) 1999-2014, Ecole des Mines de Nantes
*  All rights reserved.
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions are met:
*
*      * Redistributions of source code must retain the above copyright
*        notice, this list of conditions and the following disclaimer.
*      * Redistributions in binary form must reproduce the above copyright
*        notice, this list of conditions and the following disclaimer in the
*        documentation and/or other materials provided with the distribution.
*      * Neither the name of the Ecole des Mines de Nantes nor the
*        names of its contributors may be used to endorse or promote products
*        derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package solver.constraints.nary.automata.FA;

import dk.brics.automaton.*;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntIntHashMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import gnu.trove.set.hash.TIntHashSet;
import org.slf4j.LoggerFactory;
import util.tools.StringUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
* Created by IntelliJ IDEA.
* User: julien
* Date: Mar 15, 2010
* Time: 12:53:23 PM
*/
public class FiniteAutomaton implements IAutomaton {


    protected final static TIntIntHashMap charFromIntMap = new TIntIntHashMap();
    protected final static TIntIntHashMap intFromCharMap = new TIntIntHashMap();

    public static org.slf4j.Logger LOGGER = LoggerFactory.getLogger("solver");


    static {
        int delta = 0;
        for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; i++) {
            while ((char) (i + delta) == '"' || (char) (i + delta) == '{' || (char) (i + delta) == '}' || (char) (i + delta) == '<' ||
                    (char) (i + delta) == '>' || (char) (i + delta) == '[' || (char) (i + delta) == ']' ||
                    (char) (i + delta) == '(' || (char) (i + delta) == ')') delta++;
            charFromIntMap.put(i, i + delta);
            intFromCharMap.put(i + delta, i);
        }

    }

    public static int getIntFromChar(char c) {
        return intFromCharMap.get(c);
    }

    public static char getCharFromInt(int i) {
        return (char) charFromIntMap.get(i);
    }


    protected Automaton representedBy;

    protected TObjectIntHashMap<State> stateToIndex;
    protected ArrayList<State> states;
    protected TIntHashSet alphabet;
    protected int nbStates;


    public FiniteAutomaton() {
        this.representedBy = new Automaton();
        this.stateToIndex = new TObjectIntHashMap<State>();
        this.states = new ArrayList<State>();

        this.alphabet = new TIntHashSet();

    }

    public FiniteAutomaton(String regexp) {
        this();
        String correct = StringUtils.toCharExp(regexp);
        this.representedBy = new RegExp(correct).toAutomaton();
        for (State s : representedBy.getStates()) {
            for (Transition t : s.getTransitions()) {
                for (char c = t.getMin(); c <= t.getMax(); c++) {
                    alphabet.add(getIntFromChar(c));
                }
            }
        }
        syncStates();
    }

    public FiniteAutomaton(FiniteAutomaton other) {
        perfectCopy(other);
    }

    private void perfectCopy(FiniteAutomaton other) {
        this.representedBy = new Automaton();
        this.states = new ArrayList<State>();
        this.stateToIndex = new TObjectIntHashMap<State>();
        this.alphabet = new TIntHashSet();
        this.nbStates = other.nbStates;
        for (int i = 0; i < other.nbStates; i++) {
            State s = new State();
            this.states.add(s);
            this.stateToIndex.put(s, i);
            if (other.isFinal(i))
                s.setAccept(true);
            if (other.getInitialState() == i)
                this.representedBy.setInitialState(s);
        }
        List<int[]> transitions = other.getTransitions();
        for (int[] t : transitions) {
            this.addTransition(t[0], t[1], t[2]);
        }

    }

    private FiniteAutomaton(Automaton a, TIntHashSet alphabet) {
        this();
        fill(a, alphabet);

    }


    public static int max(TIntHashSet hs) {
        int max = Integer.MIN_VALUE;
        for (TIntIterator it = hs.iterator(); it.hasNext(); ) {
            int n = it.next();
            if (n > max)
                max = n;
        }
        return max;
    }

    private static int min(TIntHashSet hs) {
        int min = Integer.MAX_VALUE;
        for (TIntIterator it = hs.iterator(); it.hasNext(); ) {
            int n = it.next();
            if (n < min)
                min = n;
        }
        return min;
    }

    public void fill(Automaton a, TIntHashSet alphabet) {

        int max = max(alphabet);
        int min = min(alphabet);


        this.setDeterministic(a.isDeterministic());

        HashMap<State, State> m = new HashMap<State, State>();
        Set<State> states = a.getStates();
        for (State s : states) {
            this.addState();
            State ns = this.states.get(this.states.size() - 1);
            m.put(s, ns);

        }
        for (State s : states) {
            State p = m.get(s);
            int source = stateToIndex.get(p);
            p.setAccept(s.isAccept());
            if (a.getInitialState().equals(s))
                representedBy.setInitialState(p);
            for (Transition t : s.getTransitions()) {
                int tmin = getIntFromChar(t.getMin());
                int tmax = getIntFromChar(t.getMax());
                State dest = m.get(t.getDest());
                int desti = stateToIndex.get(dest);
                int minmax = Math.min(max, tmax);
                for (int i = Math.max(min, tmin); i <= minmax; i++) {
                    if (alphabet.contains(i))
                        this.addTransition(source, desti, i);
                }
            }

        }
    }

    public int getNbStates() {
        return nbStates;
    }

    public int getNbSymbols() {
        return alphabet.size();
    }

    public int addState() {
        int idx = states.size();
        State s = new State();
        states.add(s);
        stateToIndex.put(s, idx);
        nbStates++;
        return idx;
    }


    public void removeSymbolFromAutomaton(int symbol) {
        char c = getCharFromInt(symbol);
        ArrayList<Triple> triples = new ArrayList<Triple>();
        for (int i = 0; i < states.size(); i++) {
            State s = states.get(i);
            for (Transition t : s.getTransitions()) {

                if (t.getMin() <= c && t.getMax() >= c) {
                    triples.add(new Triple(i, stateToIndex.get(t.getDest()), symbol));
                }
            }
            for (Triple t : triples) {
                this.deleteTransition(t.a, t.b, t.c);
            }
            triples.clear();
        }
        alphabet.remove(symbol);
        //this.representedBy.reduce();
        // this.syncStates();
    }

    public void addTransition(int source, int destination, int... symbols) {
        for (int symbol : symbols) {
            try {
                checkState(source, destination);
            } catch (StateNotInAutomatonException e) {
                LOGGER.warn("Unable to addTransition : " + e);
            }
            alphabet.add(symbol);
            State s = states.get(source);
            State d = states.get(destination);
            s.addTransition(new Transition(getCharFromInt(symbol), d));
        }
    }

    public void deleteTransition(int source, int destination, int symbol) {
        try {
            checkState(source, destination);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to delete transition : " + e);
        }
        State s = states.get(source);
        State d = states.get(destination);
        Set<Transition> transitions = s.getTransitions();
        Set<Transition> nTrans = new HashSet<Transition>();
        char c = getCharFromInt(symbol);
        Iterator<Transition> it = transitions.iterator();
        for (; it.hasNext(); ) {
            Transition t = it.next();
            if (t.getDest().equals(d) && t.getMin() <= c && t.getMax() >= c) {
                it.remove();

                if (t.getMin() == c && c < t.getMax()) {
                    nTrans.add(new Transition((char) (c + 1), t.getMax(), d));
                } else if (t.getMin() > c && c == t.getMax()) {
                    nTrans.add(new Transition(t.getMin(), (char) (c - 1), d));
                } else if (t.getMin() < c && c < t.getMax()) {
                    nTrans.add(new Transition(t.getMin(), (char) (c - 1), d));
                    nTrans.add(new Transition((char) (c + 1), t.getMax(), d));
                }
            }
        }
        transitions.addAll(nTrans);
    }

    private void checkState(int... state) throws StateNotInAutomatonException {
        int sz = states.size();
        for (int s : state)
            if (s >= sz) {
                throw new StateNotInAutomatonException(s);
            }
    }

    public int delta(int source, int symbol) throws NonDeterministicOperationException {
        if (!representedBy.isDeterministic()) {
            throw new NonDeterministicOperationException();
        }
        try {
            checkState(source);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to perform delta lookup, state not in automaton : " + e);
        }
        State s = states.get(source);
        State d = s.step(getCharFromInt(symbol));
        if (d != null) {
            return stateToIndex.get(d);
        } else
            return -1;

    }

    private HashSet<State> nexts = new HashSet<State>();

    public void delta(int source, int symbol, TIntHashSet states) {
        try {
            checkState(source);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable perform delta lookup, state not in automaton : " + e);
        }
        State s = this.states.get(source);
        nexts.clear();
        s.step(getCharFromInt(symbol), nexts);
        for (State to : nexts) {
            states.add(stateToIndex.get(to));
        }
    }


    public TIntArrayList getOutSymbols(int source) {
        try {
            checkState(source);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to get outgoing transition, state not in automaton : " + e);
        }
        TIntHashSet set = new TIntHashSet();
        State s = states.get(source);
        for (Transition t : s.getTransitions()) {
            for (char c = t.getMin(); c <= t.getMax(); c++) {
                set.add(getIntFromChar(c));
            }
        }
        return new TIntArrayList(set.toArray());

    }

    private TIntHashSet tmpSet = new TIntHashSet();

    public int[] getOutSymbolsArray(int source) {
        try {
            checkState(source);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to get outgoing transition, state not in automaton : " + e);
        }
        tmpSet.clear();
        State s = states.get(source);
        for (Transition t : s.getTransitions()) {
            for (char c = t.getMin(); c <= t.getMax(); c++) {
                tmpSet.add(getIntFromChar(c));
            }
        }
        return tmpSet.toArray();

    }

    public void addToAlphabet(int a) {
        alphabet.add(a);
    }

    public void removeFromAlphabet(int a) {
        alphabet.remove(a);
    }

    public int getInitialState() {
        State s = representedBy.getInitialState();
        if (s == null)
            return -1;
        else
            return stateToIndex.get(s);
    }

    public boolean isFinal(int state) {
        try {
            checkState(state);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to check if this state is final : " + e);
        }
        return states.get(state).isAccept();
    }

    public void setInitialState(int state) {
        try {
            checkState(state);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to set initial state, state is not in automaton : " + e);
        }
        representedBy.setInitialState(states.get(state));
    }

    public void setFinal(int state) {
        try {
            checkState(state);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to set final state, state is not in automaton : " + e);
        }
        states.get(state).setAccept(true);
    }

    public void setFinal(int... states) {
        for (int s : states) setFinal(s);
    }

    public void setNonFinal(int state) {
        try {
            checkState(state);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to set non final state, state is not in automaton : " + e);
        }
        states.get(state).setAccept(false);
    }

    public void setNonFInal(int... states) {
        for (int s : states) setNonFinal(s);
    }

    public boolean run(int[] word) {
        StringBuilder b = new StringBuilder();
        for (int i : word) {
            char c = getCharFromInt(i);
            b.append(c);
        }
        return representedBy.run(b.toString());
    }

    public Automaton makeBricsAutomaton() {
        return representedBy.clone();
    }

    public IAutomaton repeat() {
        return new FiniteAutomaton(this.representedBy.repeat(), alphabet);
    }

    public IAutomaton repeat(int min) {
        return new FiniteAutomaton(this.representedBy.repeat(min), alphabet);
    }

    public IAutomaton repeat(int min, int max) {
        return new FiniteAutomaton(this.representedBy.repeat(min, max), alphabet);
    }

    public void minimize() {
        this.representedBy.minimize();
        syncStates();
    }

    private void syncStates() {
        this.alphabet.clear();
        this.states.clear();
        this.stateToIndex.clear();
        int idx = 0;
        for (State s : representedBy.getStates()) {
            states.add(s);
            stateToIndex.put(s, idx++);
            for (Transition t : s.getTransitions()) {
                for (char c = t.getMin(); c <= t.getMax(); c++) {
                    alphabet.add(getIntFromChar(c));
                }
            }
        }
        nbStates = states.size();
    }

    public void reduce() {
        this.representedBy.reduce();
        syncStates();
    }

    public void removeDeadTransitions() {
        this.representedBy.removeDeadTransitions();
        syncStates();
    }

    public FiniteAutomaton union(FiniteAutomaton otherI) {
        FiniteAutomaton other = (FiniteAutomaton) otherI;
        Automaton union = this.representedBy.union(other.representedBy);
        TIntHashSet alphabet = new TIntHashSet(this.alphabet.toArray());
        alphabet.addAll(other.alphabet.toArray());
        return new FiniteAutomaton(union, alphabet);

    }

    public FiniteAutomaton intersection(IAutomaton otherI) {
        FiniteAutomaton other = (FiniteAutomaton) otherI;
        Automaton inter = this.representedBy.intersection(other.representedBy);
        TIntHashSet alphabet = new TIntHashSet();
        for (int a : this.alphabet.toArray()) {
            if (other.alphabet.contains(a))
                alphabet.add(a);
        }
        return new FiniteAutomaton(inter, alphabet);
    }

    public FiniteAutomaton complement(TIntHashSet alphabet) {
        Automaton comp = this.representedBy.complement();
        return new FiniteAutomaton(comp, alphabet);
    }

    public FiniteAutomaton complement() {
        return complement(alphabet);
    }


    public FiniteAutomaton concatenate(FiniteAutomaton otherI) {
        FiniteAutomaton other = (FiniteAutomaton) otherI;
        Automaton conc = this.representedBy.concatenate(other.representedBy);
        TIntHashSet alphabet = new TIntHashSet(this.alphabet.toArray());
        alphabet.addAll(other.alphabet.toArray());
        return new FiniteAutomaton(conc, alphabet);
    }

    public void addEpsilon(int source, int destination) {
        try {
            checkState(source, destination);
        } catch (StateNotInAutomatonException e) {
            LOGGER.warn("Unable to add epsilon transition, a state is not in the automaton : " + e);

        }
        State s = states.get(source);
        State d = states.get(destination);


        ArrayList<StatePair> pairs = new ArrayList<StatePair>();
        pairs.add(new StatePair(s, d));
        this.representedBy.addEpsilons(pairs);
    }

    public boolean isDeterministic() {
        return this.representedBy.isDeterministic();
    }

    public void setDeterministic(boolean deterministic) {
        this.representedBy.setDeterministic(deterministic);
    }

    public TIntHashSet getFinalStates() {
        TIntHashSet finals = new TIntHashSet();
        for (int i = 0; i < states.size(); i++) {
            if (states.get(i).isAccept())
                finals.add(i);
        }
        return finals;
    }


    public void toDotty(String f) {
        String s = this.toDot();
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(new File(f)));
            bw.write(s);
            bw.close();
        } catch (IOException e) {
            System.err.println("Unable to write dotty file " + f);
        }
    }

    public String toDot() {
        StringBuilder b = new StringBuilder("digraph Automaton {\n");
        b.append("  rankdir = LR;\n");
        Set<State> states = this.representedBy.getStates();
        // setStateNumbers(states);
        for (State s : states) {
            int idx = stateToIndex.get(s);
            b.append("  ").append(idx);
            if (s.isAccept())
                b.append(" [shape=doublecircle];\n");
            else
                b.append(" [shape=circle];\n");
            if (s == this.representedBy.getInitialState()) {
                b.append("  initial [shape=plaintext,label=\"\"];\n");
                b.append("  initial -> ").append(idx).append("\n");
            }
            for (Transition t : s.getTransitions()) {
                b.append("  ").append(idx);
                appendDot(t, b);
            }
        }
        return b.append("}\n").toString();
    }

    private void appendDot(Transition t, StringBuilder b) {
        int destIdx = stateToIndex.get(t.getDest());

        b.append(" -> ").append(destIdx).append(" [label=\"");
        b.append("{");
        b.append(getIntFromChar(t.getMin()));
        if (t.getMin() != t.getMax()) {
            for (char c = (char) (t.getMin() + 1); c <= t.getMax(); c++) {
                b.append(",");
                b.append(getIntFromChar(c));
            }
        }
        b.append("}");
        b.append("\"]\n");
    }

    public TIntHashSet getAlphabet() {
        return alphabet;
    }

    public List<int[]> getTransitions() {
        List<int[]> transitions = new ArrayList<int[]>();
        for (int i = 0; i < states.size(); i++) {
            State s = states.get(i);
            for (Transition t : s.getTransitions()) {
                int dest = stateToIndex.get(t.getDest());
                for (char c = t.getMin(); c <= t.getMax(); c++) {
                    int symbol = getIntFromChar(c);
                    transitions.add(new int[]{i, dest, symbol});
                }
            }
        }
        return transitions;
    }


    public List<int[]> getTransitions(int state) {
        List<int[]> transitions = new ArrayList<int[]>();
        for (Transition t : states.get(state).getTransitions()) {
            int dest = stateToIndex.get(t.getDest());
            for (char c = t.getMin(); c <= t.getMax(); c++) {
                int symbol = getIntFromChar(c);
                transitions.add(new int[]{state, dest, symbol});
            }
        }
        return transitions;
    }

    public ArrayList<int[]> _removeSymbolFromAutomaton(int alpha) {
        char c = getCharFromInt(alpha);
        TIntHashSet setOfRemoved = new TIntHashSet();
        ArrayList<Triple> triples = new ArrayList<Triple>();
        for (int i = 0; i < states.size(); i++) {
            State s = states.get(i);
            for (Transition t : s.getTransitions()) {

                if (t.getMin() <= c && t.getMax() >= c) {
                    triples.add(new Triple(i, stateToIndex.get(t.getDest()), alpha));
                    setOfRemoved.add(i);
                }
            }
            for (Triple t : triples) {
                this.deleteTransition(t.a, t.b, t.c);
            }
            triples.clear();

        }
        alphabet.remove(alpha);
        // this.removeDeadTransitions();
        ArrayList<int[]> couple = new ArrayList<int[]>();
        for (int i = 0; i < states.size(); i++) {
            State s = states.get(i);
            for (Transition t : s.getTransitions()) {
                int dest = stateToIndex.get(t.getDest());
                if (setOfRemoved.contains(dest)) {
                    for (char d = t.getMin(); d <= t.getMax(); d++)
                        couple.add(new int[]{i, getIntFromChar(d)});
                }

            }


        }
        return couple;


        //this.representedBy.reduce();
        // this.syncStates();


    }

    public FiniteAutomaton clone() throws CloneNotSupportedException {
        FiniteAutomaton auto = (FiniteAutomaton) super.clone();
        auto.representedBy = new Automaton();
        auto.states = new ArrayList<State>();
        auto.stateToIndex = new TObjectIntHashMap<State>();
        auto.alphabet = new TIntHashSet();
        auto.nbStates = this.nbStates;
        for (int i = 0; i < this.nbStates; i++) {
            State s = new State();
            auto.states.add(s);
            auto.stateToIndex.put(s, i);
            if (this.isFinal(i))
                s.setAccept(true);
            if (this.getInitialState() == i)
                auto.representedBy.setInitialState(s);
        }
        List<int[]> transitions = this.getTransitions();
        for (int[] t : transitions) {
            auto.addTransition(t[0], t[1], t[2]);
        }
        return auto;
    }


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

Related Classes of solver.constraints.nary.automata.FA.FiniteAutomaton

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.