| SinglePhaseTransducer |

    1   /*
    2    *  SinglePhaseTransducer.java - transducer class
    3    *
    4    *  Copyright (c) 1998-2001, The University of Sheffield.
    5    *
    6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
    7    *  software, licenced under the GNU Library General Public License,
    8    *  Version 2, June 1991 (in the distribution as file licence.html,
    9    *  and also available at http://gate.ac.uk/gate/licence.html).
    10   *
    11   *  Hamish Cunningham, 24/07/98
    12   *
    13   *  $Id: SinglePhaseTransducer.java,v 1.57 2001/11/20 09:16:58 nasso Exp $
    14   */
    15
    16
    17  package gate.jape;
    18
    19  import java.io.*;
    20
    21  import gate.annotation.*;
    22  import gate.util.*;
    23  import gate.*;
    24  import gate.fsm.*;
    25  import gate.gui.*;
    26  import gate.creole.*;
    27  import gate.event.*;
    28  import java.util.*;
    29
    30  /**
    31    * Represents a complete CPSL grammar, with a phase name, options and
    32    * rule set (accessible by name and by sequence).
    33    * Implements a transduce method taking a Document as input.
    34    * Constructs from String or File.
    35    */
    36  public class SinglePhaseTransducer
    37  extends Transducer implements JapeConstants, java.io.Serializable
    38  {
    39    /** Debug flag */
    40    private static final boolean DEBUG = false;
    41
    42    /** Construction from name. */
    43    public SinglePhaseTransducer(String name) {
    44      this.name = name;
    45      rules = new PrioritisedRuleList();
    46      finishedAlready = false;
    47    } // Construction from name
    48
    49    /** Type of rule application (constants defined in JapeConstants). */
    50    private int ruleApplicationStyle = BRILL_STYLE;
    51
    52    /** Set the type of rule application (types defined in JapeConstants). */
    53    public void setRuleApplicationStyle(int style) {
    54      ruleApplicationStyle = style;
    55    }
    56
    57    /** The list of rules in this transducer. Ordered by priority and
    58      * addition sequence (which will be file position if they come from
    59      * a file).
    60      */
    61    private PrioritisedRuleList rules;
    62
    63    FSM fsm;
    64
    65    public FSM getFSM(){
    66      return fsm;
    67    }
    68
    69    /** Add a rule. */
    70    public void addRule(Rule rule) {
    71      rules.add(rule);
    72    } // addRule
    73
    74    /** The values of any option settings given. */
    75    private java.util.HashMap optionSettings = new java.util.HashMap();
    76
    77    /** Add an option setting. If this option is set already, the new
    78      * value overwrites the previous one.
    79      */
    80    public void setOption(String name, String setting) {
    81      optionSettings.put(name, setting);
    82    } // setOption
    83
    84    /** Get the value for a particular option. */
    85    public String getOption(String name) {
    86      return (String) optionSettings.get(name);
    87    } // getOption
    88
    89    /** Whether the finish method has been called or not. */
    90    private boolean finishedAlready;
    91
    92    /** Finish: replace dynamic data structures with Java arrays; called
    93      * after parsing.
    94      */
    95    public void finish() {
    96      // both MPT and SPT have finish called on them by the parser...
    97      if(finishedAlready)
    98        return;
    99      else
    100       finishedAlready = true;
    101
    102     for(Iterator i = rules.iterator(); i.hasNext(); )
    103       ((Rule) i.next()).finish();
    104     //build the finite state machine transition graph
    105     fsm = new FSM(this);
    106     //clear the old style data structures
    107     rules.clear();
    108     rules = null;
    109   } // finish
    110
    111 //dam: was
    112 //  private void addAnnotationsByOffset(Map map, SortedSet keys, Set annotations){
    113   private void addAnnotationsByOffset(/*Map map,*/ SimpleSortedSet keys, Set annotations){
    114     Iterator annIter = annotations.iterator();
    115     while(annIter.hasNext()){
    116       Annotation ann = (Annotation)annIter.next();
    117       //ignore empty annotations
    118       long offset = ann.getStartNode().getOffset().longValue();
    119       if(offset == ann.getEndNode().getOffset().longValue())
    120         continue;
    121 //dam: was
    122 /*
    123 //      Long offset = ann.getStartNode().getOffset();
    124
    125       List annsAtThisOffset = null;
    126       if(keys.add(offset)){
    127         annsAtThisOffset = new LinkedList();
    128         map.put(offset, annsAtThisOffset);
    129       }else{
    130         annsAtThisOffset = (List)map.get(offset);
    131       }
    132       annsAtThisOffset.add(ann);
    133 */
    134 //dam: end
    135       keys.add(offset, ann);
    136     }
    137   }//private void addAnnotationsByOffset()
    138
    139
    140   /**
    141     * Transduce a document using the annotation set provided and the current
    142     * rule application style.
    143     */
    144   public void transduce(Document doc, AnnotationSet inputAS,
    145                         AnnotationSet outputAS) throws JapeException,
    146                                                        ExecutionException {
    147     interrupted = false;
    148     fireProgressChanged(0);
    149
    150     //the input annotations will be read from this map
    151     //maps offset to list of annotations
    152
    153 //dam was
    154 /*
    155     Map annotationsByOffset = new HashMap();
    156
    157     SortedSet offsets = new TreeSet();
    158 */
    159 //dam: now
    160     SimpleSortedSet offsets = new SimpleSortedSet();
    161     SimpleSortedSet annotationsByOffset = offsets;
    162 //dam: end
    163
    164     //select only the annotations of types specified in the input list
    165 //    Out.println("Input:" + input);
    166     if(input.isEmpty())
    167     {
    168 //dam: was
    169 //        addAnnotationsByOffset(annotationsByOffset, offsets, inputAS);
    170 //dam: now
    171         addAnnotationsByOffset(offsets, inputAS);
    172 //dam: end
    173     } else {
    174       Iterator typesIter = input.iterator();
    175       AnnotationSet ofOneType = null;
    176       while(typesIter.hasNext()){
    177         ofOneType = inputAS.get((String)typesIter.next());
    178         if(ofOneType != null){
    179 //dam: was
    180 //        addAnnotationsByOffset(annotationsByOffset, offsets, ofOneType);
    181 //dam: now
    182           addAnnotationsByOffset(offsets, ofOneType);
    183 //dam: end
    184         }
    185       }
    186     }
    187
    188     if(annotationsByOffset.isEmpty()){
    189       fireProcessFinished();
    190       return;
    191     }
    192
    193     annotationsByOffset.sort();
    194     //define data structures
    195     //FSM instances that haven't blocked yet
    196 //    java.util.LinkedList activeFSMInstances = new java.util.LinkedList();
    197     java.util.ArrayList activeFSMInstances = new java.util.ArrayList();
    198
    199     // FSM instances that have reached a final state
    200     // This is a sorted set and the contained objects are sorted by the length
    201     // of the document content covered by the matched annotations
    202 //dam: was ArrayList has faster add and remove methods then LinkedList
    203 //    java.util.LinkedList acceptingFSMInstances = new LinkedList();
    204 //dam: now
    205     java.util.ArrayList acceptingFSMInstances = new ArrayList();
    206 //dam: end
    207     FSMInstance currentFSM;
    208
    209
    210     //find the first node of the document
    211     Node startNode = ((Annotation)
    212                       ((ArrayList)annotationsByOffset.
    213                              get(offsets.first())).get(0)).
    214                       getStartNode();
    215
    216     //used to calculate the percentage of processing done
    217     long lastNodeOff = doc.getContent().size().longValue();
    218
    219     //the offset of the node where the matching currently starts
    220     //the value -1 marks no more annotations to parse
    221     long startNodeOff = startNode.getOffset().longValue();
    222
    223     //used to decide when to fire progress events
    224     long oldStartNodeOff = 0;
    225
    226     //the big while for the actual parsing
    227     while(startNodeOff != -1){
    228 //Out.prln();
    229 //Out.pr("Start: " + startNodeOff);
    230       //while there are more annotations to parse
    231       //create initial active FSM instance starting parsing from new startNode
    232       //currentFSM = FSMInstance.getNewInstance(
    233       currentFSM = new FSMInstance(
    234                   fsm,
    235                   fsm.getInitialState(),//fresh start
    236                   startNode,//the matching starts form the current startNode
    237                   startNode,//current position in AG is the start position
    238                   new java.util.HashMap(),//no bindings yet!
    239                   doc
    240                   );
    241
    242       // at this point ActiveFSMInstances should always be empty!
    243       activeFSMInstances.clear();
    244       acceptingFSMInstances.clear();
    245 //dam: was used LinkedList
    246 //      activeFSMInstances.addLast(currentFSM);
    247 //dam: now used ArrayList
    248       activeFSMInstances.add(currentFSM);
    249 //dam: end
    250
    251       //far each active FSM Instance, try to advance
    252       whileloop2:
    253       while(!activeFSMInstances.isEmpty()){
    254         if(interrupted) throw new ExecutionInterruptedException(
    255           "The execution of the \"" + getName() +
    256           "\" Jape transducer has been abruptly interrupted!");
    257
    258 //Out.pr(" <" + acceptingFSMInstances.size() + "/" +
    259 //              activeFSMInstances.size() +">");
    260         // take the first active FSM instance
    261         currentFSM = (FSMInstance)activeFSMInstances.remove(0);
    262
    263         // process the current FSM instance
    264         if(currentFSM.getFSMPosition().isFinal()){
    265           //the current FSM is in a final state
    266 //dam: was LinkedList
    267 //          acceptingFSMInstances.addLast(currentFSM.clone());
    268 //dam: now
    269           acceptingFSMInstances.add(currentFSM.clone());
    270 //dam: end
    271 //          //if we are in APPELT mode clear all the accepting instances
    272 //          //apart from the longest one
    273 //          if(ruleApplicationStyle == APPELT_STYLE &&
    274 //             acceptingFSMInstances.size() > 1){
    275 //            Object longestAcceptor = acceptingFSMInstances.last();
    276 //            acceptingFSMInstances.clear();
    277 //            acceptingFSMInstances.add(longestAcceptor);
    278 //          }
    279           //if we're only looking for the shortest stop here
    280           if(ruleApplicationStyle == FIRST_STYLE) break whileloop2;
    281         }
    282
    283         //get all the annotations that start where the current FSM finishes
    284 //<<< DAM: was using SortedSet
    285 //        SortedSet offsetsTailSet = offsets.tailSet(
    286 //=== DAM: now
    287         SimpleSortedSet offsetsTailSet = offsets.tailSet(
    288 //>>> DAM: end
    289                                     currentFSM.getAGPosition().getOffset().longValue());
    290         ArrayList paths; //was linkedList
    291
    292 //<<< DAM: SortedSet speedup
    293 /*
    294         if(offsetsTailSet.isEmpty()){
    295           paths = new ArrayList();
    296         }else{
    297           paths = (List)annotationsByOffset.get(offsetsTailSet.first());
    298         }
    299 */
    300 //=== DAM: now
    301         long theFirst = offsetsTailSet.first();
    302         if(theFirst <0)
    303           continue;
    304
    305           paths = (ArrayList)annotationsByOffset.get(theFirst);
    306 //        }
    307 //System.out.println("Paths: " + paths + "\n^localInputIndex: " + localInputIndex);
    308 //>>> DAM: end
    309
    310 //        if(!paths.isEmpty()){
    311         if(paths.isEmpty()) continue;
    312           Iterator pathsIter = paths.iterator();
    313           Annotation onePath;
    314           State currentState = currentFSM.getFSMPosition();
    315           Iterator transitionsIter;
    316 //DAM: doit without intermediate FetureMap
    317 //        FeatureMap features = null;//Factory.newFeatureMap();
    318           //foreach possible annotation
    319           while(pathsIter.hasNext()){
    320             onePath = (Annotation)pathsIter.next();
    321             transitionsIter = currentState.getTransitions().iterator();
    322             Transition currentTransition;
    323             Constraint[] currentConstraints;
    324             transitionsWhile:
    325             while(transitionsIter.hasNext()){
    326               currentTransition = (Transition)transitionsIter.next();
    327               //check if the current transition can use the curent annotation (path)
    328               currentConstraints =
    329                            currentTransition.getConstraints().getConstraints();
    330               String annType;
    331 //DAM: introduce index of the constaint to process
    332               int currentConstraintsindex = -1;
    333               //we assume that all annotations in a contraint are of the same type
    334               for(int i = 0; i<currentConstraints.length; i++){
    335                 annType = currentConstraints[i].getAnnotType();
    336                 //if wrong type try next transition
    337                 if(!annType.equals(onePath.getType()))continue transitionsWhile;
    338 //DAM: doit without intermediate FetureMap
    339 //                features.clear();
    340 //                features.putAll(currentConstraints[i].getAttributeSeq());
    341                 currentConstraintsindex = i;
    342                 break;
    343               }
    344 // >>> was
    345 //              if(onePath.getFeatures().entrySet().containsAll(features.entrySet())){
    346 // >>> NASO, FeatArray optimization
    347               if(onePath.getFeatures().subsumes(
    348 //dam: was
    349 //                features
    350 //dam: now
    351                 currentConstraints[currentConstraintsindex].getAttributeSeq()
    352 //dam: end
    353                 )){
    354 // >>> end NASO
    355                 //we have a match
    356   //System.out.println("Match!");
    357                 //create a new FSMInstance, advance it over the current annotation
    358                 //take care of the bindings  and add it to ActiveFSM
    359                 FSMInstance newFSMI = (FSMInstance)currentFSM.clone();
    360                 newFSMI.setAGPosition(onePath.getEndNode());
    361                 newFSMI.setFSMPosition(currentTransition.getTarget());
    362                 //bindings
    363                 java.util.Map binds = newFSMI.getBindings();
    364                 java.util.Iterator labelsIter =
    365                                    currentTransition.getBindings().iterator();
    366                 String oneLabel;
    367                 AnnotationSet boundAnnots, newSet;
    368                 while(labelsIter.hasNext()){
    369                   oneLabel = (String)labelsIter.next();
    370                   boundAnnots = (AnnotationSet)binds.get(oneLabel);
    371                   if(boundAnnots != null)
    372                     newSet = new AnnotationSetImpl((AnnotationSet)boundAnnots);
    373                   else
    374                     newSet = new AnnotationSetImpl(doc);
    375                   newSet.add(onePath);
    376                   binds.put(oneLabel, newSet);
    377
    378                 }//while(labelsIter.hasNext())
    379                 activeFSMInstances.add(newFSMI);
    380 //Out.pr("^(" + newFSMI.getStartAGPosition().getOffset() +
    381 //                               "->" + newFSMI.getAGPosition().getOffset() + ")");
    382               }//if match
    383             }//while(transitionsIter.hasNext())
    384           }//while(pathsIter.hasNext())
    385 // dam: reverse the paths.isEmpty check
    386 //        }//if(paths != null)
    387 // dam
    388       }//while(!activeFSMInstances.isEmpty())
    389
    390
    391       //FIRE THE RULE
    392 //dam: use long
    393 //      Long lastAGPosition = null;
    394 //dam: now
    395       long lastAGPosition = -1;
    396 //dam: end
    397       if(acceptingFSMInstances.isEmpty()){
    398         //no rule to fire, advance to the next input offset
    399         lastAGPosition = startNodeOff + 1;
    400       } else if(ruleApplicationStyle == BRILL_STYLE) {
    401       //System.out.println("Brill acceptor");
    402         // fire the rules corresponding to all accepting FSM instances
    403         java.util.Iterator accFSMs = acceptingFSMInstances.iterator();
    404         FSMInstance currentAcceptor;
    405         RightHandSide currentRHS;
    406         lastAGPosition = startNode.getOffset().longValue();
    407
    408         while(accFSMs.hasNext()){
    409           currentAcceptor = (FSMInstance) accFSMs.next();
    410
    411           currentRHS = currentAcceptor.getFSMPosition().getAction();
    412           currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    413 //dam: use long
    414 //          Long currentAGPosition = currentAcceptor.getAGPosition().getOffset();
    415 //dam: now
    416           long currentAGPosition = currentAcceptor.getAGPosition().getOffset().longValue();
    417 //dam: end
    418           if(currentAGPosition > lastAGPosition)
    419             lastAGPosition = currentAGPosition;
    420         }
    421
    422       } else if(ruleApplicationStyle == APPELT_STYLE ||
    423                 ruleApplicationStyle == FIRST_STYLE) {
    424
    425 //System.out.println("Appelt acceptor");
    426         // AcceptingFSMInstances is an ordered structure:
    427         // just execute the longest (last) rule
    428
    429         Collections.sort(acceptingFSMInstances, Collections.reverseOrder());
    430
    431         FSMInstance currentAcceptor =(FSMInstance)acceptingFSMInstances.get(0);//get(0)
    432         if(isDebugMode()){
    433           //see if we have any conflicts
    434           Iterator accIter = acceptingFSMInstances.iterator();
    435           FSMInstance anAcceptor;
    436           List conflicts = new ArrayList();
    437           while(accIter.hasNext()){
    438             anAcceptor = (FSMInstance)accIter.next();
    439             if(anAcceptor.equals(currentAcceptor)){
    440               conflicts.add(anAcceptor);
    441             }else{
    442               break;
    443             }
    444           }
    445           if(conflicts.size() > 1){
    446             Out.prln("\nConflicts found during matching:" +
    447                      "\n================================");
    448             accIter = conflicts.iterator();
    449             int i = 0;
    450             while(accIter.hasNext()){
    451               Out.prln(i++ + ") " + accIter.next().toString());
    452             }
    453           }
    454         }
    455
    456         RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
    457         currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    458         //advance in AG
    459         lastAGPosition = currentAcceptor.getAGPosition().getOffset().longValue();
    460       }
    461 //      else if(ruleApplicationStyle == FIRST_STYLE) {
    462 //        // AcceptingFSMInstances is an ordered structure:
    463 //        // just execute the shortest (first) rule
    464 //
    465 //        FSMInstance currentAcceptor =(FSMInstance)acceptingFSMInstances.first();
    466 //        RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
    467 //        currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    468 //        //advance in AG
    469 //        long lastAGPosition = currentAcceptor.getAGPosition().
    470 //                              getOffset().longValue();
    471 //        //advance the index on input
    472 //        while(inputIndex < annotations.size() &&
    473 //              ((Annotation)annotations.get(inputIndex)).
    474 //              getStartNode().getOffset().longValue() < lastAGPosition){
    475 //          inputIndex++;
    476 //        }
    477 //      }
    478       else throw new RuntimeException("Unknown rule application style!");
    479
    480
    481       //advance on input
    482 //      SortedSet OffsetsTailSet = offsets.tailSet(lastAGPosition);
    483       SimpleSortedSet OffsetsTailSet = offsets.tailSet(lastAGPosition);
    484 //<<< DAM: isEmpty speedup
    485 /*
    486       if(OffsetsTailSet.isEmpty()){
    487 */
    488 //=== DAM: now
    489         long theFirst = OffsetsTailSet.first();
    490       if( theFirst < 0){
    491 //>>> DAM: end
    492         //no more input, phew! :)
    493         startNodeOff = -1;
    494         fireProcessFinished();
    495       }else{
    496 //<<< DAM: use long
    497 /*
    498         Long nextKey = (Long)OffsetsTailSet.first();
    499 */
    500 //=== DAM: now
    501         long nextKey = theFirst;
    502 //>>> DAM: end
    503         startNode = ((Annotation)
    504                       ((ArrayList)annotationsByOffset.get(nextKey)).get(0)). //nextKey
    505                     getStartNode();
    506         startNodeOff = startNode.getOffset().longValue();
    507
    508         //eliminate the possibility for infinite looping
    509         if(oldStartNodeOff == startNodeOff){
    510 //Out.prln("");
    511 //Out.pr("SKIP " + startNodeOff);
    512           //we are about to step twice in the same place, ...skip ahead
    513           lastAGPosition = startNodeOff + 1;
    514           OffsetsTailSet = offsets.tailSet(lastAGPosition);
    515 //<<< DAM: isEmpty speedup
    516 /*
    517           if(OffsetsTailSet.isEmpty()){
    518 */
    519 //=== DAM: now
    520           theFirst = OffsetsTailSet.first();
    521           if(theFirst < 0){
    522 //>>> DAM: end
    523             //no more input, phew! :)
    524             startNodeOff = -1;
    525             fireProcessFinished();
    526           }else{
    527 //<<< DAM: use long
    528 //            nextKey = (Long)OffsetsTailSet.first();
    529 //=== DAM: now
    530             nextKey = theFirst;
    531 //>>> DAM: end
    532             startNode = ((Annotation)
    533                           ((List)annotationsByOffset.get(theFirst)).get(0)).
    534                         getStartNode();
    535             startNodeOff =startNode.getOffset().longValue();
    536           }
    537 //Out.prln(" ->" + startNodeOff);
    538         }//if(oldStartNodeOff == startNodeOff)
    539
    540
    541         //fire the progress event
    542         if(startNodeOff - oldStartNodeOff > 256){
    543           if(isInterrupted()) throw new ExecutionInterruptedException(
    544             "The execution of the \"" + getName() +
    545             "\" Jape transducer has been abruptly interrupted!");
    546
    547           fireProgressChanged((int)(100 * startNodeOff / lastNodeOff));
    548           oldStartNodeOff = startNodeOff;
    549         }
    550       }
    551     }//while(startNodeOff != -1)
    552     fireProcessFinished();
    553   } // transduce
    554
    555
    556
    557   /**
    558     * Transduce a document using the annotation set provided and the current
    559     * rule application style.
    560     */
    561   public void transduce1(Document doc, AnnotationSet annotationSet)
    562                                                           throws JapeException {
    563     fireProgressChanged(0);
    564
    565     //the input annotations will be read from this set
    566     AnnotationSet annotations = null;
    567
    568     //select only the annotations of types specified in the input list
    569     //Out.println("Input:" + input);
    570     if(input.isEmpty()) annotations = annotationSet;
    571     else{
    572       Iterator typesIter = input.iterator();
    573       AnnotationSet ofOneType = null;
    574       while(typesIter.hasNext()){
    575         ofOneType = annotationSet.get((String)typesIter.next());
    576         if(ofOneType != null){
    577     //Out.println("Adding " + ofOneType.getAllTypes());
    578           if(annotations == null) annotations = ofOneType;
    579           else annotations.addAll(ofOneType);
    580         }
    581       }
    582     }
    583     if(annotations == null) annotations = new AnnotationSetImpl(doc);
    584     //Out.println("Actual input types: " + annotations.getAllTypes() + "\n"+
    585     //         "Actual input values: " + annotations + "\n===================");
    586     //INITIALISATION Should we move this someplace else?
    587     //build the finite state machine transition graph
    588     FSM fsm = new FSM(this);
    589
    590
    591     //define data structures
    592     //FSM instances that haven't blocked yet
    593     java.util.LinkedList activeFSMInstances = new java.util.LinkedList();
    594
    595     // FSM instances that have reached a final state
    596     // This is a sorted set and the contained objects are sorted by the length
    597     // of the document content covered by the matched annotations
    598     java.util.SortedSet acceptingFSMInstances = new java.util.TreeSet();
    599     FSMInstance currentFSM;
    600
    601     // startNode: the node from the current matching attepmt starts.
    602     // initially startNode = leftMost node
    603     gate.Node startNode = annotations.firstNode();
    604
    605     // if there are no annotations return
    606     if(startNode == null) return;
    607
    608     // The last node: where the parsing will stop
    609     gate.Node lastNode = annotations.lastNode();
    610     int oldStartNodeOff = 0;
    611     int lastNodeOff = lastNode.getOffset().intValue();
    612     int startNodeOff;
    613     //the big while for the actual parsing
    614     while(startNode != lastNode){
    615       //System.out.println("Offset: " + startNode.getOffset());
    616       //while there are more annotations to parse
    617       //create initial active FSM instance starting parsing from new startNode
    618       //currentFSM = FSMInstance.getNewInstance(
    619       currentFSM = new FSMInstance(
    620                   fsm,
    621                   fsm.getInitialState(),//fresh start
    622                   startNode,//the matching starts form the current startNode
    623                   startNode,//current position in AG is the start position
    624                   new java.util.HashMap(),//no bindings yet!
    625                   doc
    626                   );
    627       // at this point ActiveFSMInstances should always be empty!
    628       activeFSMInstances.addLast(currentFSM);
    629         while(!activeFSMInstances.isEmpty()){
    630         // while there are some "alive" FSM instances
    631         // take the first active FSM instance
    632         currentFSM = (FSMInstance)activeFSMInstances.removeFirst();
    633         // process the current FSM instance
    634         if(currentFSM.getFSMPosition().isFinal()){
    635           // if the current FSM is in a final state
    636           acceptingFSMInstances.add(currentFSM.clone());
    637           //  Out.println("==========================\n" +
    638           //                     "New Accepting FSM:\n" + currentFSM +
    639           //                     "\n==========================");
    640         }
    641
    642         // this will (should) be optimised
    643         State fsmPosition = currentFSM.getFSMPosition();
    644         // System.out.println("Current FSM from:" +
    645         //                 currentFSM.getStartAGPosition().getOffset() +
    646         //                 " to " + currentFSM.getAGPosition().getOffset());
    647 // >>> dam: was set
    648 /*
    649         java.util.Set transitions = fsmPosition.getTransitions();
    650 */
    651 // >>> dam: TransArray optimisation
    652         gate.util.SimpleArraySet transitions = fsmPosition.getTransitions();
    653 // >>> dam: end
    654         java.util.Iterator transIter = transitions.iterator();
    655         while(transIter.hasNext()){
    656           // System.out.print("..");
    657
    658           //for each transition, check if it is possible and "DO IT!"
    659           Transition currentTrans = (Transition)transIter.next();
    660           //holds all the matched annotations. In case of success all these
    661           //annotations will be added to the bindings Map for the new
    662           //FSMInstance
    663           //...using LinkedList instead of HashSet because Annotation does not
    664           //implement hashCode()
    665
    666           //get an empty annotation set.
    667           AnnotationSet matchedAnnots = new AnnotationSetImpl(doc);
    668
    669           //maps String to gate.FeatureMap
    670           java.util.Map constraintsByType = new java.util.HashMap();
    671           Constraint[] currentConstraints =
    672                        currentTrans.getConstraints().getConstraints();
    673           String annType;
    674           FeatureMap newAttributes, oldAttributes;
    675
    676           for(int i=0; i < currentConstraints.length; i++){
    677             annType = currentConstraints[i].getAnnotType();
    678             newAttributes = currentConstraints[i].getAttributeSeq();
    679             oldAttributes = (FeatureMap)constraintsByType.get(annType);
    680             if(newAttributes == null){
    681               if(oldAttributes == null){
    682                 //no constraints about this type.
    683                 constraintsByType.put(annType, Factory.newFeatureMap());
    684               }
    685             } else {
    686               //newAttributes != null
    687               if(oldAttributes != null) newAttributes.putAll(oldAttributes);
    688               constraintsByType.put(annType, newAttributes);
    689             }
    690           }//for(int i=0; i < currentConstraints.length; i++)
    691           //try to match all the constraints
    692
    693           boolean success = true;
    694           java.util.Iterator typesIter = constraintsByType.keySet().iterator();
    695           AnnotationSet matchedHere = null;
    696           Long offset;
    697
    698           while(success && typesIter.hasNext()) {
    699             //System.out.print("++");
    700             //do a query for each annotation type
    701             annType = (String)typesIter.next();
    702             newAttributes = (FeatureMap)constraintsByType.get(annType);
    703             offset = currentFSM.getAGPosition().getOffset();
    704             matchedHere = annotations.get(annType,
    705                                           newAttributes,
    706                                           offset);
    707             if(matchedHere == null || matchedHere.isEmpty()) success = false;
    708             else{
    709               // we have some matched annotations of the current type
    710               // let's add them to the list of matched annotations
    711               matchedAnnots.addAll(matchedHere);
    712             }
    713           } // while(success && typesIter.hasNext())
    714           if(success){
    715             // System.out.println("Success!");
    716             // create a new FSMInstance, make it advance in AG and in FSM,
    717             // take care of its bindings data structure and
    718             // add it to the list of active FSMs.
    719             FSMInstance newFSMI = (FSMInstance)currentFSM.clone();
    720             newFSMI.setAGPosition(matchedAnnots.lastNode());
    721             newFSMI.setFSMPosition(currentTrans.getTarget());
    722             // do the bindings
    723
    724             // all the annotations matched here will be added to the sets
    725             // corresponding to the labels in this list in case of succesful
    726             // matching
    727             java.util.Iterator labelsIter =
    728                                           currentTrans.getBindings().iterator();
    729             AnnotationSet oldSet, newSet;
    730             String label;
    731             java.util.Map binds = newFSMI.getBindings();
    732             while(labelsIter.hasNext()){
    733               // for each label add the set of matched annotations to the set of
    734               // annotations currently bound to that name
    735               label = (String)labelsIter.next();
    736               oldSet = (AnnotationSet)binds.get(label);
    737               if(oldSet != null){
    738                 newSet = new AnnotationSetImpl(oldSet);
    739                 newSet.addAll(matchedAnnots);
    740               }else{
    741                 newSet = new AnnotationSetImpl(matchedAnnots);
    742               }
    743               binds.put(label, newSet);
    744             } // while(labelsIter.hasNext())
    745             activeFSMInstances.addLast(newFSMI);
    746           }
    747         } // while(transIter.hasNext())
    748        // return currentFSM to the rightful owner :)
    749        // FSMInstance.returnInstance(currentFSM);
    750        } // while(!activeFSMInstances.isEmpty())
    751
    752        //FIRE THE RULE
    753       if(acceptingFSMInstances.isEmpty()){
    754         // System.out.println("\nNo match...");
    755         // advance to next relevant node in the Annotation Graph
    756         startNode = annotations.nextNode(startNode);
    757
    758         // System.out.println("111111111");
    759
    760         // check to see if there are any annotations starting here
    761         AnnotationSet annSet = annotations.get(startNode.getOffset());
    762
    763         // System.out.println("22222222");
    764
    765         if(annSet == null || annSet.isEmpty()){
    766           // System.out.println("No way to advance... Bail!");
    767           // no more starting annotations beyond this point
    768           startNode = lastNode;
    769         } else {
    770           // System.out.print("Advancing...");
    771           // advance to the next node that has starting annotations
    772           startNode = ((Annotation)annSet.iterator().next()).getStartNode();
    773           // System.out.println("done");
    774         }
    775
    776       /*
    777         AnnotationSet res = annotations.get(startNode.getOffset());
    778         if(!res.isEmpty())
    779           startNode = ((Annotation)res.iterator().next()).getStartNode();
    780         else startNode = lastNode;
    781       */
    782       } else if(ruleApplicationStyle == BRILL_STYLE) {
    783         // fire the rules corresponding to all accepting FSM instances
    784         java.util.Iterator accFSMs = acceptingFSMInstances.iterator();
    785         FSMInstance currentAcceptor;
    786         RightHandSide currentRHS;
    787 //        long lastAGPosition = startNode.getOffset().longValue();
    788         int lastAGPosition = startNode.getOffset().intValue();
    789         //  Out.println("XXXXXXXXXXXXXXXXXXXX All the accepting FSMs are:");
    790
    791         while(accFSMs.hasNext()){
    792           currentAcceptor = (FSMInstance) accFSMs.next();
    793           //  Out.println("==========================\n" +
    794                   //                     currentAcceptor +
    795                   //                     "\n==========================");
    796
    797           currentRHS = currentAcceptor.getFSMPosition().getAction();
    798           currentRHS.transduce(doc, annotations, currentAcceptor.getBindings());
    799
    800 //          long currentAGPosition =
    801 //               currentAcceptor.getAGPosition().getOffset().longValue();
    802           int currentAGPosition =
    803                currentAcceptor.getAGPosition().getOffset().intValue();
    804           if(lastAGPosition <= currentAGPosition){
    805             startNode = currentAcceptor.getAGPosition();
    806             lastAGPosition = currentAGPosition;
    807           }
    808         }
    809       // Out.println("XXXXXXXXXXXXXXXXXXXX");
    810       } else if(ruleApplicationStyle == APPELT_STYLE) {
    811         // AcceptingFSMInstances is an ordered structure:
    812         // just execute the longest (last) rule.
    813         FSMInstance currentAcceptor =
    814                                     (FSMInstance)acceptingFSMInstances.last();
    815         RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
    816         currentRHS.transduce(doc, annotations, currentAcceptor.getBindings());
    817         //advance in AG
    818         startNode = currentAcceptor.getAGPosition();
    819
    820       } else throw new RuntimeException("Unknown rule application style!");
    821       //release all the accepting instances as they have done their job
    822       /*
    823         Iterator acceptors = acceptingFSMInstances.iterator();
    824         while(acceptors.hasNext())
    825         FSMInstance.returnInstance((FSMInstance)acceptors.next());
    826       */
    827       acceptingFSMInstances.clear();
    828       startNodeOff = startNode.getOffset().intValue();
    829
    830       if(startNodeOff - oldStartNodeOff > 1024){
    831         fireProgressChanged(100 * startNodeOff / lastNodeOff);
    832         oldStartNodeOff = startNodeOff;
    833       }
    834     } // while(startNode != lastNode)
    835     // FSMInstance.clearInstances();
    836     fireProcessFinished();
    837   } // transduce
    838
    839
    840
    841
    842
    843
    844
    845   /**
    846     * Transduce a document using the annotation set provided and the current
    847     * rule application style.
    848     */
    849   public void transduce2(Document doc, AnnotationSet inputAS,
    850                         AnnotationSet outputAS) throws JapeException {
    851     fireProgressChanged(0);
    852
    853     //the input annotations will be read from this set
    854     AnnotationSet annotations = null;
    855
    856     //select only the annotations of types specified in the input list
    857     //Out.println("Input:" + input);
    858     if(input.isEmpty()) annotations = inputAS;
    859     else{
    860       annotations = new AnnotationSetImpl(doc);
    861       Iterator typesIter = input.iterator();
    862       AnnotationSet ofOneType = null;
    863       while(typesIter.hasNext()){
    864         ofOneType = inputAS.get((String)typesIter.next());
    865         if(ofOneType != null){
    866     //Out.println("Adding " + ofOneType.getAllTypes());
    867           annotations.addAll(ofOneType);
    868         }
    869       }
    870     }
    871     if(annotations == null) annotations = new AnnotationSetImpl(doc);
    872
    873     //define data structures
    874     //FSM instances that haven't blocked yet
    875     java.util.LinkedList activeFSMInstances = new java.util.LinkedList();
    876
    877     // FSM instances that have reached a final state
    878     // This is a sorted set and the contained objects are sorted by the length
    879     // of the document content covered by the matched annotations
    880     java.util.SortedSet acceptingFSMInstances = new java.util.TreeSet();
    881     FSMInstance currentFSM;
    882
    883     // startNode: the node from the current matching attepmt starts.
    884     // initially startNode = leftMost node
    885     gate.Node startNode = annotations.firstNode();
    886
    887     // if there are no annotations return
    888     if(startNode == null) return;
    889
    890     // The last node: where the parsing will stop
    891     gate.Node lastNode = annotations.lastNode();
    892     int oldStartNodeOff = 0;
    893     int lastNodeOff = lastNode.getOffset().intValue();
    894     int startNodeOff;
    895     //the big while for the actual parsing
    896     while(startNode != lastNode){
    897       //while there are more annotations to parse
    898       //create initial active FSM instance starting parsing from new startNode
    899       //currentFSM = FSMInstance.getNewInstance(
    900       currentFSM = new FSMInstance(
    901                   fsm,
    902                   fsm.getInitialState(),//fresh start
    903                   startNode,//the matching starts form the current startNode
    904                   startNode,//current position in AG is the start position
    905                   new java.util.HashMap(),//no bindings yet!
    906                   doc
    907                   );
    908       // at this point ActiveFSMInstances should always be empty!
    909       activeFSMInstances.clear();
    910       acceptingFSMInstances.clear();
    911       activeFSMInstances.addLast(currentFSM);
    912       whileloop2:
    913       while(!activeFSMInstances.isEmpty()){
    914 //System.out.println("Active instances " + activeFSMInstances.size());
    915         // while there are some "alive" FSM instances
    916         // take the first active FSM instance
    917         currentFSM = (FSMInstance)activeFSMInstances.removeFirst();
    918         // process the current FSM instance
    919         if(currentFSM.getFSMPosition().isFinal()){
    920           // if the current FSM is in a final state
    921           acceptingFSMInstances.add(currentFSM.clone());
    922           //if we are in APPELT mode clear all the accepting instances
    923           //apart from the longest one
    924           if(ruleApplicationStyle == APPELT_STYLE &&
    925              acceptingFSMInstances.size() > 1){
    926             Object longestAcceptor = acceptingFSMInstances.last();
    927             acceptingFSMInstances.clear();
    928             acceptingFSMInstances.add(longestAcceptor);
    929           }
    930           //if we're only looking for the shortest stop here
    931           if(ruleApplicationStyle == FIRST_STYLE) break whileloop2;
    932         }
    933         //all the annotations that start from the current node.
    934         AnnotationSet paths = annotations.get(
    935                                 currentFSM.getAGPosition().getOffset());
    936         if(paths != null){
    937           Iterator pathsIter = paths.iterator();
    938           Annotation onePath;
    939           State currentState = currentFSM.getFSMPosition();
    940           Iterator transitionsIter;
    941           FeatureMap features = Factory.newFeatureMap();
    942           //foreach possible annotation
    943           while(pathsIter.hasNext()){
    944             onePath = (Annotation)pathsIter.next();
    945             transitionsIter = currentState.getTransitions().iterator();
    946             Transition currentTransition;
    947             Constraint[] currentConstraints;
    948             transitionsWhile:
    949             while(transitionsIter.hasNext()){
    950               currentTransition = (Transition)transitionsIter.next();
    951               //check if the current transition can use the curent annotation (path)
    952               currentConstraints =
    953                            currentTransition.getConstraints().getConstraints();
    954               String annType;
    955               //we assume that all annotations in a contraint are of the same type
    956               for(int i = 0; i<currentConstraints.length; i++){
    957                 annType = currentConstraints[i].getAnnotType();
    958                 //if wrong type try next transition
    959                 if(!annType.equals(onePath.getType()))continue transitionsWhile;
    960                 features.clear();
    961                 features.putAll(currentConstraints[i].getAttributeSeq());
    962               }
    963               if(onePath.getFeatures().entrySet().containsAll(features.entrySet())){
    964                 //we have a match
    965   //System.out.println("Match!");
    966                 //create a new FSMInstance, advance it over the current annotation
    967                 //take care of the bindings  and add it to ActiveFSM
    968                 FSMInstance newFSMI = (FSMInstance)currentFSM.clone();
    969                 newFSMI.setAGPosition(onePath.getEndNode());
    970                 newFSMI.setFSMPosition(currentTransition.getTarget());
    971                 //bindings
    972                 java.util.Map binds = newFSMI.getBindings();
    973                 java.util.Iterator labelsIter =
    974                                    currentTransition.getBindings().iterator();
    975                 String oneLabel;
    976                 AnnotationSet boundAnnots, newSet;
    977                 while(labelsIter.hasNext()){
    978                   oneLabel = (String)labelsIter.next();
    979                   boundAnnots = (AnnotationSet)binds.get(oneLabel);
    980                   if(boundAnnots != null){
    981                     newSet = new AnnotationSetImpl(boundAnnots);
    982                   }else{
    983                     newSet = new AnnotationSetImpl(doc);
    984                   }
    985                   newSet.add(onePath);
    986                   binds.put(oneLabel, newSet);
    987                 }//while(labelsIter.hasNext())
    988                 activeFSMInstances.addLast(newFSMI);
    989               }//if match
    990             }//while(transitionsIter.hasNext())
    991           }//while(pathsIter.hasNext())
    992         }//if(paths != null)
    993       }//while(!activeFSMInstances.isEmpty())
    994
    995       Node newStartNode = null;
    996       //FIRE THE RULE
    997       if(acceptingFSMInstances.isEmpty()){
    998 //System.out.println("No acceptor");
    999         //no rule to fire just advance to next relevant node in the
    1000        //Annotation Graph
    1001//System.out.print(startNode.getOffset());
    1002        newStartNode = annotations.nextNode(startNode);
    1003//System.out.println("->" + startNode.getOffset());
    1004        // check to see if there are any annotations starting here
    1005        AnnotationSet annSet = annotations.get(newStartNode.getOffset());
    1006
    1007        if(annSet == null || annSet.isEmpty()){
    1008          // no more starting annotations beyond this point
    1009          newStartNode = lastNode;
    1010        } else {
    1011          // advance to the next node that has starting annotations
    1012          newStartNode = ((Annotation)annSet.iterator().next()).getStartNode();
    1013        }
    1014      } else if(ruleApplicationStyle == BRILL_STYLE) {
    1015      //System.out.println("Brill acceptor");
    1016        // fire the rules corresponding to all accepting FSM instances
    1017        java.util.Iterator accFSMs = acceptingFSMInstances.iterator();
    1018        FSMInstance currentAcceptor;
    1019        RightHandSide currentRHS;
    1020//        long lastAGPosition = startNode.getOffset().longValue();
    1021        int lastAGPosition = startNode.getOffset().intValue();
    1022        //  Out.println("XXXXXXXXXXXXXXXXXXXX All the accepting FSMs are:");
    1023
    1024        while(accFSMs.hasNext()){
    1025          currentAcceptor = (FSMInstance) accFSMs.next();
    1026          //  Out.println("==========================\n" +
    1027                  //                     currentAcceptor +
    1028                  //                     "\n==========================");
    1029
    1030          currentRHS = currentAcceptor.getFSMPosition().getAction();
    1031          currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    1032
    1033//          long currentAGPosition =
    1034//               currentAcceptor.getAGPosition().getOffset().longValue();
    1035          int currentAGPosition =
    1036               currentAcceptor.getAGPosition().getOffset().intValue();
    1037          if(lastAGPosition <= currentAGPosition){
    1038            newStartNode = currentAcceptor.getAGPosition();
    1039            lastAGPosition = currentAGPosition;
    1040          }
    1041        }
    1042      // Out.println("XXXXXXXXXXXXXXXXXXXX");
    1043      } else if(ruleApplicationStyle == APPELT_STYLE) {
    1044//System.out.println("Appelt acceptor");
    1045        // AcceptingFSMInstances is an ordered structure:
    1046        // just execute the longest (last) rule
    1047
    1048        FSMInstance currentAcceptor =(FSMInstance)acceptingFSMInstances.last();
    1049        RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
    1050        currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    1051        //advance in AG
    1052        newStartNode = currentAcceptor.getAGPosition();
    1053
    1054      } else if(ruleApplicationStyle == FIRST_STYLE) {
    1055//System.out.println("Appelt acceptor");
    1056        // AcceptingFSMInstances is an ordered structure:
    1057        // just execute the shortest (first) rule
    1058
    1059        FSMInstance currentAcceptor =(FSMInstance)acceptingFSMInstances.first();
    1060        RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
    1061        currentRHS.transduce(doc, outputAS, currentAcceptor.getBindings());
    1062        //advance in AG
    1063//System.out.print(startNode.getOffset());
    1064        newStartNode = currentAcceptor.getAGPosition();
    1065//System.out.println("->" + startNode.getOffset());
    1066      } else throw new RuntimeException("Unknown rule application style!");
    1067       startNodeOff = newStartNode.getOffset().intValue();
    1068
    1069      //fire the progress event
    1070      if(startNodeOff - oldStartNodeOff > 1024){
    1071        fireProgressChanged(100 * startNodeOff / lastNodeOff);
    1072        oldStartNodeOff = startNodeOff;
    1073      }
    1074      if(startNode == newStartNode){
    1075        //no advance: we probably matched some annotations that cover no text
    1076        //we should force the advance
    1077        Err.prln("Infinite loop detected in grammar " + getName() +
    1078                 " at position " + startNodeOff + " in " + doc.getSourceUrl() +
    1079                 "!\nAdvancing forced!");
    1080        newStartNode = annotations.nextNode(startNode);
    1081        // check to see if there are any annotations starting here
    1082        AnnotationSet annSet = annotations.get(newStartNode.getOffset());
    1083        if(annSet == null || annSet.isEmpty()){
    1084          // no more starting annotations beyond this point
    1085          newStartNode = lastNode;
    1086        } else {
    1087          // advance to the next node that has starting annotations
    1088          newStartNode = ((Annotation)annSet.iterator().next()).getStartNode();
    1089        }
    1090      }
    1091      startNode = newStartNode;
    1092//System.out.println("->" + startNodeOff);
    1093    } // while(startNode != lastNode)
    1094    // FSMInstance.clearInstances();
    1095    fireProcessFinished();
    1096  } // transduce
    1097
    1098
    1099  //###############end modified versions
    1100
    1101  /** Clean up (delete action class files, for e.g.). */
    1102  public void cleanUp() {
    1103//    for(DListIterator i = rules.begin(); ! i.atEnd(); i.advance())
    1104//      ((Rule) i.get()).cleanUp();
    1105  } // cleanUp
    1106
    1107  /** A string representation of this object. */
    1108  public String toString() {
    1109    return toString("");
    1110  } // toString()
    1111
    1112  /** A string representation of this object. */
    1113  public String toString(String pad) {
    1114    String newline = Strings.getNl();
    1115    String newPad = Strings.addPadding(pad, INDENT_PADDING);
    1116
    1117    StringBuffer buf =
    1118      new StringBuffer(pad + "SPT: name(" + name + "); ruleApplicationStyle(");
    1119
    1120    switch(ruleApplicationStyle) {
    1121      case APPELT_STYLE: buf.append("APPELT_STYLE); "); break;
    1122      case BRILL_STYLE:  buf.append("BRILL_STYLE); ");  break;
    1123      default: break;
    1124    }
    1125
    1126    buf.append("rules(" + newline);
    1127    Iterator rulesIterator = rules.iterator();
    1128    while(rulesIterator.hasNext())
    1129      buf.append(((Rule) rulesIterator.next()).toString(newPad) + " ");
    1130
    1131    buf.append(newline + pad + ")." + newline);
    1132
    1133    return buf.toString();
    1134  } // toString(pad)
    1135
    1136  //needed by fsm
    1137  public PrioritisedRuleList getRules() {
    1138    return rules;
    1139  }
    1140
    1141  /**
    1142    * Adds a new type of input annotations used by this transducer.
    1143    * If the list of input types is empty this transducer will parse all the
    1144    * annotations in the document otherwise the types not found in the input
    1145    * list will be completely ignored! To be used with caution!
    1146    */
    1147  public void addInput(String ident) {
    1148    input.add(ident);
    1149  }
    1150  public synchronized void removeProgressListener(ProgressListener l) {
    1151    if (progressListeners != null && progressListeners.contains(l)) {
    1152      Vector v = (Vector) progressListeners.clone();
    1153      v.removeElement(l);
    1154      progressListeners = v;
    1155    }
    1156  }
    1157  public synchronized void addProgressListener(ProgressListener l) {
    1158    Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
    1159    if (!v.contains(l)) {
    1160      v.addElement(l);
    1161      progressListeners = v;
    1162    }
    1163  }
    1164
    1165  /**
    1166    * Defines the types of input annotations that this transducer reads. If this
    1167    * set is empty the transducer will read all the annotations otherwise it
    1168    * will only "see" the annotations of types found in this list ignoring all
    1169    * other types of annotations.
    1170    */
    1171  java.util.Set input = new java.util.HashSet();
    1172  private transient Vector progressListeners;
    1173
    1174  protected void fireProgressChanged(int e) {
    1175    if (progressListeners != null) {
    1176      Vector listeners = progressListeners;
    1177      int count = listeners.size();
    1178      for (int i = 0; i < count; i++) {
    1179        ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
    1180      }
    1181    }
    1182  }
    1183  protected void fireProcessFinished() {
    1184    if (progressListeners != null) {
    1185      Vector listeners = progressListeners;
    1186      int count = listeners.size();
    1187      for (int i = 0; i < count; i++) {
    1188        ((ProgressListener) listeners.elementAt(i)).processFinished();
    1189      }
    1190    }
    1191  }
    1192  public int getRuleApplicationStyle() {
    1193    return ruleApplicationStyle;
    1194  }
    1195
    1196  /*
    1197  private void writeObject(ObjectOutputStream oos) throws IOException {
    1198    Out.prln("writing spt");
    1199    oos.defaultWriteObject();
    1200    Out.prln("finished writing spt");
    1201  } // writeObject
    1202  */
    1203
    1204
    1205} // class SinglePhaseTransducer
    1206
    1207/*
    1208class SimpleSortedSet {
    1209
    1210    static final int INCREMENT = 1023;
    1211    int[] theArray = new int[INCREMENT];
    1212    Object[] theObject = new Object[INCREMENT];
    1213    int tsindex = 0;
    1214    int size = 0;
    1215    public static int avesize = 0;
    1216    public static int maxsize = 0;
    1217    public static int avecount = 0;
    1218    public SimpleSortedSet()
    1219    {
    1220        avecount++;
    1221        java.util.Arrays.fill(theArray, Integer.MAX_VALUE);
    1222    }
    1223
    1224    public Object get(int elValue)
    1225    {
    1226        int index = java.util.Arrays.binarySearch(theArray, elValue);
    1227        if (index >=0)
    1228            return theObject[index];
    1229        return null;
    1230    }
    1231
    1232    public boolean add(int elValue, Object o)
    1233    {
    1234        int index = java.util.Arrays.binarySearch(theArray, elValue);
    1235        if (index >=0)
    1236        {
    1237            ((ArrayList)theObject[index]).add(o);
    1238            return false;
    1239        }
    1240        if (size == theArray.length)
    1241        {
    1242            int[] temp = new int[theArray.length + INCREMENT];
    1243            Object[] tempO = new Object[theArray.length + INCREMENT];
    1244            System.arraycopy(theArray, 0, temp, 0, theArray.length);
    1245            System.arraycopy(theObject, 0, tempO, 0, theArray.length);
    1246            java.util.Arrays.fill(temp, theArray.length, temp.length , Integer.MAX_VALUE);
    1247            theArray = temp;
    1248            theObject = tempO;
    1249        }
    1250        index = ~index;
    1251        System.arraycopy(theArray, index, theArray, index+1, size - index );
    1252        System.arraycopy(theObject, index, theObject, index+1, size - index );
    1253        theArray[index] = elValue;
    1254        theObject[index] = new ArrayList();
    1255        ((ArrayList)theObject[index]).add(o);
    1256        size++;
    1257        return true;
    1258    }
    1259    public int first()
    1260    {
    1261        if (tsindex >= size) return -1;
    1262        return theArray[tsindex];
    1263    }
    1264
    1265    public Object getFirst()
    1266    {
    1267        if (tsindex >= size) return null;
    1268        return theObject[tsindex];
    1269    }
    1270
    1271    public SimpleSortedSet tailSet(int elValue)
    1272    {
    1273        if (tsindex < theArray.length && elValue != theArray[tsindex])
    1274        {
    1275            if (tsindex<(size-1) && elValue > theArray[tsindex] &&
    1276                elValue <= theArray[tsindex+1])
    1277                {
    1278                    tsindex++;
    1279                   return this;
    1280                }
    1281            int index = java.util.Arrays.binarySearch(theArray, elValue);
    1282            if (index < 0)
    1283                index = ~index;
    1284            tsindex = index;
    1285        }
    1286        return this;
    1287    }
    1288
    1289    public boolean isEmpty()
    1290    {
    1291        return size ==0;
    1292    }
    1293};
    1294*/

| SinglePhaseTransducer |