State.java
001 /*
002  *  State.java
003  *
004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Valentin Tablan, 11/Apr/2000
013  *
014  *  $Id: State.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015  */
016 
017 package gate.fsm;
018 
019 import java.util.ArrayList;
020 import java.util.HashMap;
021 import java.util.Iterator;
022 
023 import gate.jape.*;
024 import gate.util.SimpleArraySet;
025 
026 /**
027  * This class implements a Finite State Machine state.
028  *
029  */
030 public class State implements JapeConstants {
031 
032   /** Debug flag
033    */
034 
035   private static final boolean DEBUG = false;
036   
037   public static final int UNKNOWN_INDEX = 1;
038   public static final int VISITED_INDEX = -2;
039   public static final int UNVISITED_INDEX = 2;
040   public static final int INITIAL_INDEX = 0;
041   public static final String INITIAL_RULE = "_____Initial_State_for_all_rules";
042   public static final String UNKNOWN_RULE = "___UNKNOWN_RULES_TYPE_1";
043   public static final String UNVISITED_RULE = "___UNKNOWN_RULES_TYPE_2";
044   
045   // Points to the rule in the FSM which created this state
046   private int indexInRuleList = UNVISITED_INDEX;
047   
048   /**
049    
050    @return  The index of the rule in the ruleTimes ArrayList held in the FSM
051    */
052   public int getIndexInRuleList() {
053     return indexInRuleList;
054   }
055 
056   /**
057    * This should only need to be called by getRuleForState when the state is being initialized
058    @param indexInRuleList
059    */
060   void setIndexInRuleList(int indexInRuleList) {
061     this.indexInRuleList = indexInRuleList;
062   }
063   
064   /**
065    * Sets the index of the rule for this state.
066    * Determines the appropriate rule by recursively searching this state's outbound transitions until
067    * we reach a final state.  Record this state in the ruleTimes and ruleNameToIndexMap structures
068    @param ruleNameToIndexMap
069    @param ruleTimes
070    @return
071    */
072   public int getRuleForState(HashMap<String,Integer> ruleNameToIndexMap,ArrayList<RuleTime>ruleTimes) {
073     if (this.getIndexInRuleList() != UNVISITED_INDEX) {
074       return this.getIndexInRuleList();  
075     }
076     if (this.isFinal()) {
077       String ruleNameOfThisState = this.getAction().getRuleName();
078       int returnVal;
079       if (ruleNameToIndexMap.containsKey(ruleNameOfThisState)) {
080         returnVal =  ruleNameToIndexMap.get(ruleNameOfThisState);
081       }
082       else {
083         ruleTimes.add(new RuleTime(0,ruleNameOfThisState));
084         ruleNameToIndexMap.put(ruleNameOfThisState, ruleTimes.size() 1);
085         returnVal =  ruleTimes.size() 1;
086       }
087       this.setIndexInRuleList(returnVal);
088       return returnVal;
089     }
090     else {
091       this.setIndexInRuleList(VISITED_INDEX);
092       int returnVal = UNKNOWN_INDEX;
093       // Note that returnVal will always need to be the same for all returned elements
094       // (because a state is currently associated with only one rule), but
095       // we need to call it repeateadly to set the indexInRuleList for all states in 
096       // the tree
097       for (Transition t :this.getTransitions()) {
098         int tempReturn = t.getTarget().getRuleForState(ruleNameToIndexMap,ruleTimes);
099         if (tempReturn != UNKNOWN_INDEX && tempReturn != VISITED_INDEX) {
100           returnVal = tempReturn;
101         }
102       }
103       if (returnVal == UNKNOWN_INDEX) {
104         this.setIndexInRuleList(returnVal);
105       }
106       else {
107         this.propogateRuleForward(returnVal);
108       }
109       return returnVal;
110     }
111   }
112 
113 
114   /**
115    * This sets the rule index for every descendant of the current state
116    * Note that we only need to set the state for states whose rule is Unknown
117    * Rules whose state is "VISITED_INDEX" are my ancestors.  Their states will be set
118    * when the recursion backs out.  Rules whose index is something other than VISITED_INDEX or
119    * UNKNOWN_RULE are finished and we know that all of their descendants have been set, by
120    * the properties of this algorithm 
121    @param ruleForThisState   The rule to be associated with this state
122    */
123   private void propogateRuleForward(int ruleForThisState) {
124     this.setIndexInRuleList(ruleForThisState);
125     for (Transition t: this.getTransitions()) {
126       if (t.getTarget().getIndexInRuleList() == UNKNOWN_INDEX) {
127         t.getTarget().propogateRuleForward(ruleForThisState);
128       }
129     }
130   }
131 
132   /**
133    * Build a new state.
134    */
135   public State() {
136     myIndex = State.index++;
137     isFinal = false;
138   }
139 
140   /**
141    * Reports if this state is a final one.
142    * Note: A state has an associated action if and only if it is final.
143    */
144   public boolean isFinal() {
145     return isFinal;
146   }
147 
148   /**
149    * Gets the set of transitions for this state.
150    *
151    @return a Set contining objects of type gate.fsm.Transition
152    */
153 // >>> DAM, was Set
154 /*
155   public Set getTransitions() {
156     return transitions;
157   }
158 */
159 // >>> DAM, TransArray optimization
160   public SimpleArraySet<Transition> getTransitions() {
161     return transitions;
162   }
163 // >>> DAM, end
164   /** Sets the action associated to this FINAL state. An action is actually
165    * a gate.jape.RightHandSide object.
166    * NOTE: only a final state has an associated action so after a call to this
167    * method this state will be a final one.
168    */
169   protected void setAction(RightHandSide rhs) {
170     action = rhs;
171     isFinal = (action != null);
172   }
173 
174   /** Sets the value for fileIndex. File index is the index in the jape
175    * definition file of the rule that contains as right hand side the action
176    * associated to this state. This value is only intended for final states.
177    */
178   protected void setFileIndex(int i) { fileIndex = i; }
179 
180   /** Sets the value for priority. Priority is the priority in the jape
181    * definition file of the rule that contains as right hand side the action
182    * associated to this state. This value is only intended for final states.
183    */
184   protected void setPriority(int i) { priority = i; }
185 
186   /**
187    * Gets the action associated to this state.
188    *
189    @return a RightHandSide object
190    */
191   public RightHandSide getAction() {
192     return action;
193   }
194 
195   /**
196    * Returns the index in the definition file of the rule that generated this
197    * state.
198    * The value for fileIndex is correct only on final states!
199    */
200   int getFileIndex() { return fileIndex; }
201 
202   /**
203    * Returns the priority in the definition file of the rule that generated
204    * this state.
205    * This value is correct only on final states!
206    */
207   int getPriority() { return priority; }
208 
209   /**
210    * Adds a new transition to the list of outgoing transitions for this state.
211    *
212    @param transition the transition to be added
213    */
214   public void addTransition(Transition transition) {
215     transitions.add(transition);
216   // addTransition
217 
218   /**
219    * Gets the index of this state. Each state has a unique index (a int value).
220    * This value is not actually used by any of the algorithms. It is useful only
221    * as a way of refering to states in string representations so it is used by
222    * toString and GML related methods.
223    *
224    @return the index associated to this state
225    */
226   public int getIndex() {
227     return myIndex;
228   }// getIndex
229 
230   /**
231    * Returns a GML (graph modelling language) representation for the edges
232    * corresponding to transitions departing from this state in the
233    * transition graph of the FSM to which this state belongs
234    *
235    @return a string value contining the GML text
236    */
237   public String getEdgesGML() {
238 ///    String res = "";
239     StringBuffer res = new StringBuffer(gate.Gate.STRINGBUFFER_SIZE);
240 
241     Iterator transIter = transitions.iterator();
242     BasicPatternElement bpe;
243 
244     while(transIter.hasNext()) {
245       Transition currentTrans = (Transition)transIter.next();
246 /*      res += "edge [ source " + myIndex +
247              " target " + currentTrans.getTarget().getIndex() +
248              " label \"" + currentTrans.shortDesc() + ":";
249 */
250         res.append("edge [ source ");
251         res.append(myIndex);
252         res.append(" target ");
253         res.append(currentTrans.getTarget().getIndex());
254         res.append(" label \"");
255         res.append(currentTrans.shortDesc());
256         res.append(":");
257 
258              bpe = currentTrans.getConstraints();
259              if(bpe == null///res += "null";
260                 res.append("null");
261              else ///res += bpe.shortDesc();
262                 res.append(bpe.shortDesc());
263 ///             res += " :" + currentTrans.getBindings() +              "\" ]\n";
264              res.append(" :");
265              res.append(currentTrans.getBindings());
266              res.append("\" ]\n");
267     }
268     return res.toString();
269   // getEdgesGML
270 
271   /**
272    * Returns a textual description of this state
273    *
274    @return a String value.
275    */
276   public String toString() {
277 ///    String res = "State " + myIndex;
278     StringBuffer res = new StringBuffer(gate.Gate.STRINGBUFFER_SIZE);
279 
280     if(isFinal()) ///res += "\nFinal!";
281         res.append("\nFinal!");
282 
283     ///res += "\nTransitions:\n";
284     res.append("\nTransitions:\n");
285 
286     Iterator transIter = transitions.iterator();
287     while(transIter.hasNext()){
288       ///res += transIter.next().toString();
289       res.append(transIter.next().toString());
290     }
291     return res.toString();
292   }
293 
294 
295   /**
296    * A set of objects of type gata.fsm.Transition representing the outgoing
297    * transitions.
298    */
299 // >>> DAM was
300 /*
301   private Set transitions = new HashSet();
302 */
303 // >>> DAM, TransArray optimization
304   private SimpleArraySet<Transition> transitions = new SimpleArraySet<Transition>();
305 // >>> DAM, end
306 
307   /**
308    * Is this state a final one?
309    */
310   protected boolean isFinal = false;
311 
312   /**
313    * The right hand side associated to the rule for which this state recognizes
314    * the lhs.
315    */
316   protected RightHandSide action = null;
317 
318   /**
319    * The unique index of this state.
320    */
321   protected int myIndex;
322 
323   /**
324    * The class data member used for generating unique indices for State
325    * instances.
326    */
327   protected static int index = 0;
328 
329   /**
330    * The index in the definition file of the rule that was used for creating
331    * this state.
332    * NOTE: this member is consistent only for FINAL STATES!
333    */
334   protected int fileIndex = 0;
335 
336   /**
337    * The priority of the rule from which this state derived.
338    *
339    */
340   protected int priority = -1;
341 
342 // State