All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rationals.Automaton Maven / Gradle / Ivy

Go to download

HermiT is reasoner for ontologies written using the Web Ontology Language (OWL). Given an OWL file, HermiT can determine whether or not the ontology is consistent, identify subsumption relationships between classes, and much more. This is the maven build of HermiT and is designed for people who wish to use HermiT from within the OWL API. It is now versioned in the main HermiT version repository, although not officially supported by the HermiT developers. The version number of this package is a composite of the HermiT version and an value representing releases of this packaged version. So, 1.3.7.1 is the first release of the mavenized version of HermiT based on the 1.3.7 release of HermiT. This package includes the Jautomata library (http://jautomata.sourceforge.net/), and builds with it directly. This library appears to be no longer under active development, and so a "fork" seems appropriate. No development is intended or anticipated on this code base.

There is a newer version: 1.3.8.4
Show newest version
package rationals;

import java.util.ArrayList;
import java.util.HashMap;
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 rationals.transformations.TransformationsToolBox;

/**
 * A class defining Automaton objects
 * 
 * This class defines the notion of automaton. Following notations are used to
 * describe this class.
 * 

* An automaton is a 5-uple A = (X , Q , I , T , D) where *

    *
  • X is a finite set of labels named alphabet , *
  • Q is a finite set of states, *
  • I, included in Q, is the set of initial states, *
  • T, included in Q, is the set of terminal states *
  • and D is the set of transitions, which is included in * Q times X times Q (transitions are triples (q , l , q') * where q, q' are states and l a label). *
* The empty word, usually denoted by epsilon will be denoted here by * the symbol @. *

* In this implementation of automaton, any object may be a label, states are * instance of class State and transitions are intances of class * Transition. Only automata should create instances of states * through Automaton method newState. * @author [email protected] * @author [email protected] * @version $Id: Automaton.java 15 2008-09-20 13:29:35Z oqube $ * @see Transition State */ public class Automaton> implements Acceptor, StateMachine, Rational, Cloneable { /* the identification of this automaton */ private Object id; protected T builder; /** * @return Returns the id. */ public Object getId() { return id == null ? "automaton" : id; } /** * @param id * The id to set. */ public void setId(Object id) { this.id = id; } // The set of all objects which are labels of // transitions of this automaton. protected Set alphabet; // The set of all states of this automaton. private Set states; // the set of initial states private Set initials; // the set of terminale states private Set terminals; // Allows acces to transitions of this automaton // starting from a given state and labelled by // a given object. The keys of this map are instances // of class Key and // values are sets of transitions. private Map> transitions; // Allows acces to transitions of this automaton // arriving to a given state and labelled by // a given object. The keys of this map are instances // of class Key and // values are sets of transitions. private Map> reverse; // bonte private StateFactory stateFactory = new DefaultStateFactory(this); private Map labels = new HashMap(); /** * @return */ public StateFactory getStateFactory() { return this.stateFactory; } /** * @param factory */ public void setStateFactory(StateFactory factory) { this.stateFactory = factory; factory.setAutomaton(this); } /** * Returns an automaton which recognizes the regular language associated with * the regular expression @, where @ denotes the empty * word. * @return an automaton which recognizes @ */ public static Automaton epsilonAutomaton() { Automaton v = new Automaton(); v.addState(true, true); return v; } /** * Returns an automaton which recognizes the regular language associated with * the regular expression l, where l is a given label. * * @param label * any object that will be used as a label. * @return an automaton which recognizes label */ public static Automaton labelAutomaton(Object label) { Automaton v = new Automaton(); State start = v.addState(true, false); State end = v.addState(false, true); try { v.addTransition(new Transition(start, label, end)); } catch (NoSuchStateException x) { } return v; } /** * Returns an automaton which recognizes the regular language associated with * the regular expression u, where u is a given word. * * @param word * a List of Object interpreted as a word * @return an automaton which recognizes label */ public static Automaton labelAutomaton(List word) { Automaton v = new Automaton(); State start = null; if (word.isEmpty()) { v.addState(true, true); return v; } else start = v.addState(true, false); State end = null; try { for (Iterator i = word.iterator(); i.hasNext();) { Object o = i.next(); end = v.addState(false, !i.hasNext()); v.addTransition(new Transition(start, o, end)); start = end; } } catch (NoSuchStateException x) { } return v; } /** * Creates a new empty automaton which contains no state and no transition. An * empty automaton recognizes the empty language. */ public Automaton() { this(null); } /** * Create a new empty automaton with given state factory. * * @param sf * the StateFactory object to use for creating new states. May be * null. */ public Automaton(StateFactory sf) { this.stateFactory = sf == null ? new DefaultStateFactory(this) : sf; alphabet = new HashSet(); states = stateFactory.stateSet(); initials = stateFactory.stateSet(); terminals = stateFactory.stateSet(); transitions = new HashMap>(); reverse = new HashMap>(); } /** * Returns a new instance of state which will be initial and terminal or not * depending of parameters. * * @param initial * if true, the new state will be initial; otherwise this state will * be non initial. * @param terminal * if true, the new state will be terminal; otherwise this state will * be non terminal. * @return a new state, associated with this automaton. This new state should * be used only with this automaton in order to create a new * transition for this automaton. * @see Transition */ public State addState(boolean initial, boolean terminal) { State state = stateFactory.create(initial, terminal); if (initial) initials.add(state); if (terminal) terminals.add(state); states.add(state); return state; } /** * Returns the alphabet X associated with this automaton. * * @return the alphabet X associated with this automaton. */ public Set alphabet() { return alphabet; } /** * Returns the set of states Q associated with this automaton. * * @return the set of states Q associated with this automaton. * Objects which are contained in this set are instances of class * State. * @see State */ public Set states() { return states; } /** * Returns the set of initial states I associated with this * automaton. * * @return the set of initial states I associated with this * automaton. Objects which are contained in this set are instances of * class State. * @see State */ public Set initials() { return initials; } /** * Returns the set of terminal states T associated with this * automaton. * * @return set of terminal states T associated with this automaton. * Objects which are contained in this set are instances of class * State. * @see State */ public Set terminals() { return terminals; } // Computes and return the set of all accessible states, starting // from a given set of states and using transitions // contained in a given Map protected Set access(Set start, Map> map) { Set current = start; Set old; do { old = current; current = stateFactory.stateSet(); Iterator i = old.iterator(); while (i.hasNext()) { State e = (State) i.next(); current.add(e); Iterator j = alphabet.iterator(); while (j.hasNext()) { Iterator k = find(map, e, j.next()).iterator(); while (k.hasNext()) { current.add(((Transition) k.next()).end()); } } } } while (current.size() != old.size()); return current; } /** * Returns the set of all accessible states in this automaton. * * @return the set of all accessible states in this automaton. A state * s is accessible if there exists a path from an initial * state to s. Objects which are contained in this set are * instances of class State. * @see State */ public Set accessibleStates() { return access(initials, transitions); } /** * Returns the set of states that can be accessed in this automaton starting * from given set of states * * @param states * a non null set of starting states * @return a - possibly empty - set of accessible states */ public Set accessibleStates(Set states) { return access(states, transitions); } /* * (non-Javadoc) * * @see rationals.Rational#accessibleStates(rationals.State) */ public Set accessibleStates(State state) { Set s = stateFactory.stateSet(); s.add(state); return access(s, transitions); } /** * Returns the set of co-accesible states for a given set of states, that is * the set of states from this automaton from which there exists a path to a * state in states. * * @param states * a non null set of ending states * @return a - possibly empty - set of coaccessible states */ public Set coAccessibleStates(Set states) { return access(states, reverse); } /** * Returns the set of all co-accessible states in this automaton. * * @return the set of all co-accessible states in this automaton. A state * s is co-accessible if there exists a path from this * state s to a terminal state. Objects which are contained * in this set are instances of class State. * @see State */ public Set coAccessibleStates() { return access(terminals, reverse); } /** * Returns the set of all states which are co-accessible and accessible in * this automaton. * * @return the set of all states which are co-accessible and accessible in * this automaton. A state s is accessible if there exists * a path from an initial state to s. A state s * is co-accessible if there exists a path from this state s * to a terminal state. Objects which are contained in this set are * instances of class State. * @see State */ public Set accessibleAndCoAccessibleStates() { Set ac = accessibleStates(); ac.retainAll(coAccessibleStates()); return ac; } // Computes and return the set of all transitions, starting // from a given state and labelled by a given label // contained in a given Map protected Set find(Map> m, State e, Object l) { Key n = new Key(e, l); if (!m.containsKey(n)) return new HashSet(); return m.get(n); } // add a given transition in a given Map protected void add(Map> m, Transition t) { Key n = new Key(t.start(), t.label()); Set s; if (!m.containsKey(n)) { s = new HashSet(); m.put(n, s); } else s = m.get(n); s.add(t); } /** * Returns the set of all transitions of this automaton * * @return the set of all transitions of this automaton Objects which are * contained in this set are instances of class Transition. * @see Transition */ public Set delta() { Set s = new HashSet(); for (Set tr : transitions.values()) s.addAll(tr); return s; } /** * Returns the set of all transitions of this automaton starting from a given * state and labelled b a given label. * * @param state * a state of this automaton. * @param label * a label used in this automaton. * @return the set of all transitions of this automaton starting from state * state and labelled by label. Objects which * are contained in this set are instances of class * Transition. * @see Transition */ public Set delta(State state, Object label) { return find(transitions, state, label); } /** * Returns the set of all transitions from state from to state * to. * * @param from * starting state * @param to * ending state * @return a Set of Transition objects */ public Set deltaFrom(State from, State to) { Set t = delta(from); for (Iterator i = t.iterator(); i.hasNext();) { Transition tr = (Transition) i.next(); if (!to.equals(tr.end())) i.remove(); } return t; } /** * Return all transitions from a State * * @param state * start state * @return a new Set of transitions (maybe empty) */ public Set delta(State state) { Set s = new HashSet(); for (Object lt : alphabet) s.addAll(delta(state, lt)); return s; } /** * Returns all transitions from a given set of states. * * @param s * a Set of State objects * @return a Set of Transition objects */ public Set delta(Set s) { Set ds = new HashSet(); for (State st : s) ds.addAll(delta(st)); return ds; } /** * Return a mapping from couples (q,q') of states to all (q,l,q') transitions * from q to q' * * @return a Map */ public Map couples() { // loop on transition map keys Iterator>> it = transitions.entrySet() .iterator(); Map> ret = new HashMap>(); while (it.hasNext()) { Map.Entry> e = it.next(); // get start and end state State st = e.getKey().s; Iterator trans = e.getValue().iterator(); while (trans.hasNext()) { Transition tr = trans.next(); State nd = tr.end(); Couple cpl = new Couple(st, nd); Set s = (Set) ret.get(cpl); if (s == null) s = new HashSet(); s.add(tr); ret.put(cpl, s); } } return ret; } /** * Returns the set of all transitions of the reverse of this automaton * * @return the set of all transitions of the reverse of this automaton. A * reverse of an automaton A = (X , Q , I , T , D) is the * automaton A' = (X , Q , T , I , D') where D' * is the set { (q , l , q') | (q' , l , q) in D}. Objects * which are contained in this set are instances of class * Transition. * @see Transition */ public Set deltaMinusOne(State state, Object label) { return find(reverse, state, label); } /** * Adds a new transition in this automaton if it is a new transition for this * automaton. The parameter is considered as a new transition if there is no * transition in this automaton which is equal to the parameter in the sense * of method equals of class Transition. * * @param transition * the transition to add. * @throws NoSuchStateException * if transition is null * or if transition = (q , l , q') and q or * q' does not belong to Q the set of the states * of this automaton. */ public void addTransition(Transition transition) throws NoSuchStateException { if (!states.contains(transition.start()) || !states.contains(transition.end())) throw new NoSuchStateException(); if (!alphabet.contains(transition.label())) { alphabet.add(transition.label()); } add(transitions, transition); add(reverse, new Transition(transition.end(), transition.label(), transition.start())); } /** * the project method keeps from the Automaton only the transitions labelled * with the letters contained in the set alph, effectively computing a * projection on this alphabet. * * @param alph * the alphabet to project on */ public void projectOn(Set alph) { // remove unwanted transitions from ret Iterator>> trans = transitions.entrySet() .iterator(); Set newtrans = new HashSet(); while (trans.hasNext()) { Map.Entry> entry = trans.next(); Key k = entry.getKey(); Iterator tit = entry.getValue().iterator(); while (tit.hasNext()) { Transition tr = tit.next(); if (!alph.contains(k.l)) { // create epsilon transition newtrans.add(new Transition(k.s, null, tr.end())); // remove transtion tit.remove(); } } } // add newly created transitions if (!newtrans.isEmpty()) { for (Transition tr : newtrans) { add(transitions, tr); add(reverse, new Transition(tr.end(), tr.label(), tr.start())); } } // remove alphabet alphabet.retainAll(alph); } /** * returns a textual representation of this automaton. * * @return a textual representation of this automaton based on the converter * toAscii. * @see rationals.converters.toAscii */ public String toString() { return new rationals.converters.toAscii().toString(this); } /** * returns a copy of this automaton. * * @return a copy of this automaton with new instances of states and * transitions. */ public Object clone() { Automaton b; b = new Automaton(); Map map = new HashMap(); for (State e : states) map.put(e, b.addState(e.isInitial(), e.isTerminal())); for (Transition t : delta()) { try { b.addTransition(new Transition((State) map.get(t.start()), t.label(), (State) map.get(t.end()))); } catch (NoSuchStateException x) { } } return b; } private class Key { private State s; private Object l; protected Key(State s, Object l) { this.s = s; this.l = l; } public boolean equals(Object o) { if (o == null) return false; try { Key t = (Key) o; boolean ret = (l == null ? t.l == null : l.equals(t.l)) && (s == null ? t.s == null : s.equals(t.s)); return ret; } catch (ClassCastException x) { return false; } } public int hashCode() { int x, y; if (s == null) x = 0; else x = s.hashCode(); if (l == null) y = 0; else y = l.hashCode(); return y << 16 | x; } } /** * Returns true if this automaton accepts given word -- ie. sequence of * letters. Note that this method accepts words with letters not in this * automaton's alphabet, effectively recognizing all words from any alphabet * projected to this alphabet. *

* If you need standard recognition, use * * @see{accept(java.util.List)}. * @param word * @return */ public boolean prefixProjection(List word) { Set s = stepsProject(word); return !s.isEmpty(); } /** * Return the set of steps this automaton will be in after reading word. Note * this method skips letters not in alphabet instead of rejecting them. * * @param l * @return */ public Set stepsProject(List word) { Set s = initials(); Iterator it = word.iterator(); while (it.hasNext()) { Object o = it.next(); if (!alphabet.contains(o)) continue; s = step(s, o); if (s.isEmpty()) return s; } return s; } /* * (non-Javadoc) * * @see rationals.Acceptor#accept(java.util.List) */ public boolean accept(List word) { Set s = TransformationsToolBox.epsilonClosure(steps(word), this); s.retainAll(terminals()); return !s.isEmpty(); } /** * Return true if this automaton can accept the given word starting from given * set. Note The ending state(s) need not be terminal for this * method to return true. * * @param state * a starting state * @param word * a List of objects in this automaton's alphabet * @return true if there exists a path labelled by word from s to at least one * other state in this automaton. */ public boolean accept(State state, List word) { Set s = stateFactory.stateSet(); s.add(state); return !steps(s, word).isEmpty(); } /* * (non-Javadoc) * * @see rationals.Acceptor#steps(java.util.List) */ public Set steps(List word) { Set s = TransformationsToolBox.epsilonClosure(initials(), this); return steps(s, word); } /** * Return the set of states this automaton will be in after reading the word * from start states s. * * @param s * the set of starting states * @param word * the word to read. * @return the set of reached states. */ public Set steps(Set s, List word) { Iterator it = word.iterator(); while (it.hasNext()) { Object o = it.next(); s = step(s, o); if (s.isEmpty()) return s; } return s; } /** * Return the set of states this automaton will be in after reading the word * from singler start state s. * * @param st * the starting state * @param word * the word to read. * @return the set of reached states. */ public Set steps(State st, List word) { Set s = stateFactory.stateSet(); s.add(st); Iterator it = word.iterator(); while (it.hasNext()) { Object o = it.next(); s = step(s, o); if (s.isEmpty()) return s; } return s; } /** * Return the list of set of states this automaton will be in after reading * word from start state. Is start state is null, assume reading from * initials(). * * @param word * @param start */ public List> traceStates(List word, State start) { List> ret = new ArrayList>(); Set s = null; if (start != null) { s = stateFactory.stateSet(); s.add(start); } else { s = initials(); } Iterator it = word.iterator(); while (it.hasNext()) { Object o = it.next(); if (!alphabet.contains(o)) continue; s = step(s, o); ret.add(s); if (s.isEmpty()) return null; } return ret; } /** * Returns the size of the longest word recognized by this automaton where * letters not belonging to its alphabet are ignored. * * * @param word * @return */ public int longestPrefixWithProjection(List word) { int lret = 0; Set s = initials(); Iterator it = word.iterator(); while (it.hasNext()) { Object o = it.next(); if ((o == null) || !alphabet.contains(o)) { lret++; continue; } s = step(s, o); if (s.isEmpty()) break; lret++; } return lret; } /** * Return the set of states accessible in one transition from given set of * states s and letter o. * * @param s * @param o * @return */ public Set step(Set s, Object o) { Set ns = stateFactory.stateSet(); Set ec = TransformationsToolBox.epsilonClosure(s, this); Iterator it = ec.iterator(); while (it.hasNext()) { State st = (State) it.next(); Iterator it2 = delta(st).iterator(); while (it2.hasNext()) { Transition tr = (Transition) it2.next(); if (tr.label() != null && tr.label().equals(o)) ns.add(tr.end()); } } return ns; } /** * @param tr * @param msg */ public void updateTransitionWith(Transition tr, Object msg) { Object lbl = tr.label(); alphabet.remove(lbl); alphabet.add(msg); /* update transition map */ Key k = new Key(tr.start(), lbl); Set s = transitions.remove(k); if (s != null) transitions.put(new Key(tr.start(), msg), s); /* update reverse map */ k = new Key(tr.end(), lbl); s = (Set) reverse.remove(k); if (s != null) reverse.put(new Key(tr.end(), msg), s); tr.setLabel(msg); } /** * @param st * @return */ public Set deltaMinusOne(State st) { Set s = new HashSet(); Iterator alphit = alphabet().iterator(); while (alphit.hasNext()) { s.addAll(deltaMinusOne(st, alphit.next())); } return s; } /** * Enumerate all prefix of words of length lower or equal than i in this * automaton. This method takes exponential time and space to execute: * use with care !. * * @param i * maximal length of words. * @return a Set of List of Object */ public Set enumerate(int ln) { Set ret = new HashSet(); class EnumState { /** * @param s * @param list */ public EnumState(State s, List list) { st = s; word = new ArrayList(list); } State st; List word; } ; LinkedList ll = new LinkedList(); List cur = new ArrayList(); for (Iterator i = initials.iterator(); i.hasNext();) { State s = (State) i.next(); if (s.isTerminal()) ret.add(new ArrayList()); ll.add(new EnumState(s, cur)); } do { EnumState st = (EnumState) ll.removeFirst(); Set trs = delta(st.st); List word = st.word; for (Iterator k = trs.iterator(); k.hasNext();) { Transition tr = (Transition) k.next(); word.add(tr.label()); if (word.size() <= ln) { EnumState en = new EnumState(tr.end(), word); ll.add(en); ret.add(en.word); } word.remove(word.size() - 1); } } while (!ll.isEmpty()); return ret; } /** * Create a new state with given label. The state is created with as neither * initial nor terminal. * * @param label * the state's label. May not be null. * @return the newly created state. */ public State state(Object label) { State s = labels.get(label); if (s == null) { s = stateFactory.create(false, false); states.add(s); labels.put(label, s); } return s; } /** * Starts creation of a new transition from the given state. Note that the * state is created with given label if it does not exists. * * @param o * the label of state to create transition from. may not be null. * @return a TransitionBuilder that can be used to create a new transition. */ public T from(Object o) { return builder.build(state(o), this); } public void setBuilder(T t) { this.builder = t; } }