CorpusAnnotationDiff.java
0001 /*
0002  *  CorpusAnnotationDiff.java
0003  *
0004  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
0005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0006  *
0007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0008  *  software, licenced under the GNU Library General Public License,
0009  *  Version 2, June 1991 (in the distribution as file licence.html,
0010  *  and also available at http://gate.ac.uk/gate/licence.html).
0011  *
0012  *  Angel Kirilov (mod. AnnotationDiff), 22/Aug/2002
0013  *
0014  *  $Id: CorpusAnnotationDiff.java 17530 2014-03-04 15:57:43Z markagreenwood $
0015  */
0016 
0017 package gate.annotation;
0018 
0019 import gate.Annotation;
0020 import gate.AnnotationSet;
0021 import gate.Corpus;
0022 import gate.Document;
0023 import gate.FeatureMap;
0024 import gate.Resource;
0025 import gate.creole.AbstractResource;
0026 import gate.creole.AbstractVisualResource;
0027 import gate.creole.AnnotationSchema;
0028 import gate.creole.ResourceInstantiationException;
0029 import gate.swing.XJTable;
0030 import gate.util.Err;
0031 import gate.util.Out;
0032 import gate.util.Strings;
0033 
0034 import java.awt.Color;
0035 import java.awt.Component;
0036 import java.awt.Dimension;
0037 import java.awt.Font;
0038 import java.awt.Rectangle;
0039 import java.beans.BeanInfo;
0040 import java.beans.Introspector;
0041 import java.text.NumberFormat;
0042 import java.util.ArrayList;
0043 import java.util.Collection;
0044 import java.util.Collections;
0045 import java.util.Comparator;
0046 import java.util.HashSet;
0047 import java.util.Iterator;
0048 import java.util.LinkedList;
0049 import java.util.List;
0050 import java.util.Set;
0051 
0052 import javax.swing.Box;
0053 import javax.swing.BoxLayout;
0054 import javax.swing.JComponent;
0055 import javax.swing.JLabel;
0056 import javax.swing.JPanel;
0057 import javax.swing.JTable;
0058 import javax.swing.Scrollable;
0059 import javax.swing.SwingConstants;
0060 import javax.swing.SwingUtilities;
0061 import javax.swing.table.AbstractTableModel;
0062 import javax.swing.table.DefaultTableCellRenderer;
0063 import javax.swing.table.JTableHeader;
0064 
0065 /**
0066   * This class compare two annotation sets on annotation type given by the
0067   * AnnotationSchema object. It also deals with graphic representation of the
0068   * result.
0069   */
0070 public class CorpusAnnotationDiff extends AbstractVisualResource
0071   implements  Scrollable{
0072 
0073   private static final long serialVersionUID = 334626622328431740L;
0074 
0075   // number of pixels to be used as increment by scroller
0076   protected int maxUnitIncrement = 10;
0077 
0078   /** Debug flag */
0079   private static final boolean DEBUG = false;
0080 
0081   /** This document contains the key annotation set which is taken as reference
0082    *  in comparison*/
0083   private Document keyDocument = null;
0084 
0085   /** This corpus contains the key annotation set which is taken as reference
0086    *  in comparison*/
0087   private Corpus keyCorpus = null;
0088   
0089   /** The name of the annotation set. If is null then the default annotation set
0090     * will be considered.
0091     */
0092   private String keyAnnotationSetName = null;
0093 
0094   /** This document contains the response annotation set which is being
0095     * compared against the key annotation set.
0096     */
0097   private Document responseDocument = null;
0098 
0099   /** This corpus contains the response annotation set which is being
0100     * compared against the key annotation set.
0101     */
0102   private Corpus responseCorpus = null;
0103 
0104   /** The name of the annotation set. If is null then the default annotation set
0105     * will be considered.
0106     */
0107   private String responseAnnotationSetName = null;
0108 
0109   /** The name of the annotation set considered in calculating FalsePozitive.
0110     * If is null then the default annotation set will be considered.
0111     */
0112   private String responseAnnotationSetNameFalsePoz = null;
0113 
0114   /** The annotation schema object used to get the annotation name*/
0115   private AnnotationSchema annotationSchema = null;
0116 
0117   /** A set of feature names bellonging to annotations from keyAnnotList
0118     * used in isCompatible() and isPartiallyCompatible() methods
0119     */
0120   private Set<?> keyFeatureNamesSet = null;
0121 
0122   /** The precision strict value (see NLP Information Extraction)*/
0123   private double precisionStrict = 0.0;
0124   /** The precision lenient value (see NLP Information Extraction)*/
0125   private double precisionLenient = 0.0;
0126   /** The precision average value (see NLP Information Extraction)*/
0127   private double precisionAverage = 0.0;
0128 
0129   /** The Recall strict value (see NLP Information Extraction)*/
0130   private double recallStrict = 0.0;
0131   /** The Recall lenient value (see NLP Information Extraction)*/
0132   private double recallLenient = 0.0;
0133   /** The Recall average value (see NLP Information Extraction)*/
0134   private double recallAverage = 0.0;
0135 
0136   /** The False positive strict (see NLP Information Extraction)*/
0137   private double falsePositiveStrict = 0.0;
0138   /** The False positive lenient (see NLP Information Extraction)*/
0139   private double falsePositiveLenient = 0.0;
0140   /** The False positive average (see NLP Information Extraction)*/
0141   private double falsePositiveAverage = 0.0;
0142 
0143   /** The F-measure strict (see NLP Information Extraction)*/
0144   private double fMeasureStrict = 0.0;
0145   /** The F-measure lenient (see NLP Information Extraction)*/
0146   private double fMeasureLenient = 0.0;
0147   /** The F-measure average (see NLP Information Extraction)*/
0148   private double fMeasureAverage = 0.0;
0149   /** The weight used in F-measure (see NLP Information Extraction)*/
0150   public  static double weight = 0.5;
0151 
0152   /**  This string represents the type of annotations used to play the roll of
0153     *  total number of words needed to calculate the False Positive.
0154     */
0155   private String annotationTypeForFalsePositive = null;
0156 
0157   /** A number formater for displaying precision and recall*/
0158   private static NumberFormat formatter = NumberFormat.getInstance();
0159 
0160   /** The components that will stay into diffPanel*/
0161   private XJTable diffTable = null;
0162 
0163   /** Used to represent the result of diff. See DiffSetElement class.*/
0164   private Set<DiffSetElement> diffSet = null;
0165 
0166   /** This field is used in doDiff() and detectKeyType() methods and holds all
0167    *  partially correct keys */
0168   private Set<Annotation> keyPartiallySet = null;
0169   /** This field is used in doDiff() and detectResponseType() methods*/
0170   private Set<Annotation> responsePartiallySet = null;
0171 
0172   /** This list is created from keyAnnotationSet at init() time*/
0173   private List<Annotation> keyAnnotList = null;
0174   /** This list is created from responseAnnotationSet at init() time*/
0175   private List<Annotation> responseAnnotList = null;
0176 
0177   /** This field indicates wheter or not the annot diff should run int the text
0178    *  mode*/
0179   private boolean textMode = false;
0180 
0181   /**  Field designated to represent the max nr of annot types and coolors for
0182     *  each type
0183     **/
0184   public static final int MAX_TYPES = 5;
0185   /** A default type when all annotation are the same represented by White color*/
0186   public static final int DEFAULT_TYPE = 0;
0187   /** A correct type when all annotation are corect represented by Green color*/
0188   public static final int CORRECT_TYPE = 1;
0189   /** A partially correct type when all annotation are corect represented
0190    *  by Blue color*/
0191   public static final int PARTIALLY_CORRECT_TYPE = 2;
0192   /** A spurious type when annotations in response were not present in key.
0193    *  Represented by Red color*/
0194   public static final int SPURIOUS_TYPE = 3;
0195   /** A missing type when annotations in key were not present in response
0196    *  Represented by Yellow color*/
0197   public static final int MISSING_TYPE = 4;
0198 
0199   /** Red used for SPURIOUS_TYPE*/
0200   private  final Color RED = new Color(255,173,181);
0201   /** Green used for CORRECT_TYPE*/
0202   private  final Color GREEN = new Color(173,255,214);
0203   /** White used for DEFAULT_TYPE*/
0204   private  final Color WHITE = new Color(255,255,255);
0205   /** Blue used for PARTIALLY_CORRECT_TYPE*/
0206   private  final Color BLUE = new Color(173,215,255);
0207   /** Yellow used for MISSING_TYPE*/
0208   private  final Color YELLOW = new Color(255,231,173);
0209 
0210   /** Used in DiffSetElement to represent an empty raw in the table*/
0211   private final int NULL_TYPE = -1;
0212   /** Used in some setForeground() methods*/
0213   private  final Color BLACK = new Color(0,0,0);
0214   /** The array holding the colours according to the annotation types*/
0215   private Color colors[] new Color[MAX_TYPES];
0216 
0217   /** Used to store the no. of annotations from response,identified as belonging
0218     * to one of the previous types.
0219     */
0220   private int typeCounter[] new int[MAX_TYPES];
0221 
0222   /** Constructs a CorpusAnnotationDiff*/
0223   public CorpusAnnotationDiff(){
0224   //CorpusAnnotationDiff
0225 
0226   /** Sets the annotation type needed to calculate the falsePossitive measure
0227     @param anAnnotType is the annotation type needed to calculate a special
0228     *  mesure called falsePossitive. Usualy the value is "token", but it can be
0229     *  any other string with the same semantic.
0230     */
0231   public void setAnnotationTypeForFalsePositive(String anAnnotType){
0232     annotationTypeForFalsePositive = anAnnotType;
0233   // setAnnotationTypeForFalsePositive
0234 
0235   /** Gets the annotation type needed to calculate the falsePossitive measure
0236     @return annotation type needed to calculate a special
0237     * mesure called falsePossitive.
0238     */
0239   public String getAnnotationTypeForFalsePositive(){
0240     return annotationTypeForFalsePositive;
0241   // getAnnotationTypeForFalsePositive
0242 
0243   /** Sets the keyCorpus in AnnotDiff
0244     @param aKeyCorpus The GATE corpus used as a key in annotation diff.
0245     */
0246   public void setKeyCorpus(Corpus aKeyCorpus) {
0247     keyCorpus = aKeyCorpus;
0248   // setKeyCorpus
0249 
0250   /** @return the keyCorpus used in AnnotDiff process */
0251   public Corpus getKeyCorpus(){
0252     return keyCorpus;
0253   // getKeyCorpus
0254 
0255   /** Sets the keyAnnotationSetName in AnnotDiff
0256     @param aKeyAnnotationSetName The name of the annotation set from the
0257     * keyDocument.If aKeyAnnotationSetName is null then the default annotation
0258     * set will be used.
0259     */
0260   public void setKeyAnnotationSetName(String aKeyAnnotationSetName){
0261     keyAnnotationSetName = aKeyAnnotationSetName;
0262   // setKeyAnnotationSetName();
0263 
0264   /** Gets the keyAnnotationSetName.
0265     @return The name of the keyAnnotationSet used in AnnotationDiff. If
0266     * returns null then the the default annotation set will be used.
0267     */
0268   public String getKeyAnnotationSetName(){
0269     return keyAnnotationSetName;
0270   // getKeyAnnotationSetName()
0271 
0272   /** Sets the keyFeatureNamesSet in AnnotDiff.
0273     @param aKeyFeatureNamesSet a set containing the feature names from key
0274     * that will be used in isPartiallyCompatible()
0275     */
0276   public void setKeyFeatureNamesSet(Set<?> aKeyFeatureNamesSet){
0277     keyFeatureNamesSet = aKeyFeatureNamesSet;
0278   }//setKeyFeatureNamesSet();
0279 
0280   /** Gets the keyFeatureNamesSet in AnnotDiff.
0281     @return A set containing the feature names from key
0282     * that will be used in isPartiallyCompatible()
0283     */
0284   public Set<?> getKeyFeatureNamesSet(){
0285     return keyFeatureNamesSet;
0286   }//getKeyFeatureNamesSet();
0287 
0288   /** Sets the responseAnnotationSetName in AnnotDiff
0289     @param aResponseAnnotationSetName The name of the annotation set from the
0290     * responseDocument.If aResponseAnnotationSetName is null then the default
0291     * annotation set will be used.
0292     */
0293   public void setResponseAnnotationSetName(String aResponseAnnotationSetName){
0294     responseAnnotationSetName = aResponseAnnotationSetName;
0295   // setResponseAnnotationSetName();
0296 
0297   /** gets the responseAnnotationSetName.
0298     @return The name of the responseAnnotationSet used in AnnotationDiff. If
0299     * returns null then the the default annotation set will be used.
0300     */
0301   public String getResponseAnnotationSetName(){
0302     return responseAnnotationSetName;
0303   // getResponseAnnotationSetName()
0304 
0305   /** Sets the responseAnnotationSetNameFalsePoz in AnnotDiff
0306     @param aResponseAnnotationSetNameFalsePoz The name of the annotation set
0307     * from the responseDocument.If aResponseAnnotationSetName is null
0308     * then the default annotation set will be used.
0309     */
0310   public void setResponseAnnotationSetNameFalsePoz(
0311                                     String aResponseAnnotationSetNameFalsePoz){
0312     responseAnnotationSetNameFalsePoz = aResponseAnnotationSetNameFalsePoz;
0313   // setResponseAnnotationSetNameFalsePoz();
0314 
0315   /** gets the responseAnnotationSetNameFalsePoz.
0316     @return The name of the responseAnnotationSetFalsePoz used in
0317     * AnnotationDiff. If returns null then the the default annotation
0318     * set will be used.
0319     */
0320   public String getResponseAnnotationSetNameFalsePoz(){
0321     return responseAnnotationSetNameFalsePoz;
0322   // getResponseAnnotationSetNamefalsePoz()
0323 
0324   /**  Sets the annot diff to work in the text mode.This would not initiate the
0325     *  GUI part of annot diff but it would calculate precision etc
0326     */
0327   public void setTextMode(Boolean aTextMode){
0328     //it needs to be a Boolean and not boolean, because you cannot put
0329     //in the parameters hashmap a boolean, it needs an object
0330     textMode = aTextMode.booleanValue();
0331   }// End setTextMode();
0332 
0333   /** Gets the annot diff textmode.True means that the text mode is activated.*/
0334   public boolean isTextMode(){
0335     return textMode;
0336   }// End setTextMode();
0337 
0338   /** Returns a set with all annotations of a specific type*/
0339   public Set<Annotation> getAnnotationsOfType(int annotType){
0340     Set<Annotation> results = new HashSet<Annotation>();
0341     if (diffSet == nullreturn results;
0342     Iterator<DiffSetElement> diffIter = diffSet.iterator();
0343     while(diffIter.hasNext()){
0344       DiffSetElement diffElem = diffIter.next();
0345       switch(annotType){
0346         case CORRECT_TYPE:{
0347           if (diffElem.getRightType() == CORRECT_TYPE)
0348             results.add(diffElem.getRightAnnotation());
0349         }break;
0350         case PARTIALLY_CORRECT_TYPE:{
0351           if (diffElem.getRightType() == PARTIALLY_CORRECT_TYPE)
0352             results.add(diffElem.getRightAnnotation());
0353         }break;
0354         case SPURIOUS_TYPE:{
0355           if (diffElem.getRightType() == SPURIOUS_TYPE)
0356             results.add(diffElem.getRightAnnotation());
0357         }break;
0358         case MISSING_TYPE:{
0359           if (diffElem.getLeftType() == MISSING_TYPE)
0360             results.add(diffElem.getLeftAnnotation());
0361         }break;
0362         case DEFAULT_TYPE:{
0363           if (diffElem.getLeftType() == DEFAULT_TYPE)
0364             results.add(diffElem.getLeftAnnotation());
0365         }break;
0366       }// End switch
0367     }// End while
0368     return results;
0369   }//getAnnotationsOfType
0370 
0371   //Prameters utility methods
0372   /**
0373    * Gets the value of a parameter of this resource.
0374    @param paramaterName the name of the parameter
0375    @return the current value of the parameter
0376    */
0377   @Override
0378   public Object getParameterValue(String paramaterName)
0379                 throws ResourceInstantiationException{
0380     return AbstractResource.getParameterValue(this, paramaterName);
0381   }
0382 
0383   /**
0384    * Sets the value for a specified parameter.
0385    *
0386    @param paramaterName the name for the parameteer
0387    @param parameterValue the value the parameter will receive
0388    */
0389   @Override
0390   public void setParameterValue(String paramaterName, Object parameterValue)
0391               throws ResourceInstantiationException{
0392     // get the beaninfo for the resource bean, excluding data about Object
0393     BeanInfo resBeanInf = null;
0394     try {
0395       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
0396     catch(Exception e) {
0397       throw new ResourceInstantiationException(
0398         "Couldn't get bean info for resource " this.getClass().getName()
0399         + Strings.getNl() "Introspector exception was: " + e
0400       );
0401     }
0402     AbstractResource.setParameterValue(this, resBeanInf, paramaterName, parameterValue);
0403   }
0404 
0405   /**
0406    * Sets the values for more parameters in one step.
0407    *
0408    @param parameters a feature map that has paramete names as keys and
0409    * parameter values as values.
0410    */
0411   @Override
0412   public void setParameterValues(FeatureMap parameters)
0413               throws ResourceInstantiationException{
0414     AbstractResource.setParameterValues(this, parameters);
0415   }
0416 
0417 
0418 
0419   ///////////////////////////////////////////////////
0420   // PRECISION methods
0421   ///////////////////////////////////////////////////
0422 
0423   /** @return the precisionStrict field*/
0424   public double getPrecisionStrict(){
0425     return precisionStrict;
0426   // getPrecisionStrict
0427 
0428   /** @return the precisionLenient field*/
0429   public double getPrecisionLenient(){
0430     return precisionLenient;
0431   // getPrecisionLenient
0432 
0433   /** @return the precisionAverage field*/
0434   public double getPrecisionAverage(){
0435     return precisionAverage;
0436   // getPrecisionAverage
0437 
0438   /** @return the fMeasureStrict field*/
0439   public double getFMeasureStrict(){
0440     return fMeasureStrict;
0441   // getFMeasureStrict
0442 
0443   /** @return the fMeasureLenient field*/
0444   public double getFMeasureLenient(){
0445     return fMeasureLenient;
0446   // getFMeasureLenient
0447 
0448   /** @return the fMeasureAverage field*/
0449   public double getFMeasureAverage(){
0450     return fMeasureAverage;
0451   // getFMeasureAverage
0452 
0453   ///////////////////////////////////////////////////
0454   // RECALL methods
0455   ///////////////////////////////////////////////////
0456 
0457   /** @return the recallStrict field*/
0458   public double getRecallStrict(){
0459     return recallStrict;
0460   // getRecallStrict
0461 
0462   /** @return the recallLenient field*/
0463   public double getRecallLenient(){
0464     return recallLenient;
0465   // getRecallLenient
0466 
0467   /** @return the recallAverage field*/
0468   public double getRecallAverage(){
0469     return recallAverage;
0470   // getRecallAverage
0471 
0472   ///////////////////////////////////////////////////
0473   // FALSE POSITIVE methods
0474   ///////////////////////////////////////////////////
0475 
0476   /** @return the falsePositiveStrict field*/
0477   public double getFalsePositiveStrict(){
0478     return falsePositiveStrict;
0479   // getFalsePositiveStrict
0480 
0481   /** @return the falsePositiveLenient field*/
0482   public double getFalsePositiveLenient(){
0483     return falsePositiveLenient;
0484   // getFalsePositiveLenient
0485 
0486   /** @return the falsePositiveAverage field*/
0487   public double getFalsePositiveAverage(){
0488     return falsePositiveAverage;
0489   // getFalsePositive
0490 
0491   /**
0492     @param aResponseCorpus the GATE response corpus
0493     * containing the annotation Set being compared against the annotation from
0494     * the keyCorpus.
0495     */
0496   public void setResponseCorpus(Corpus aResponseCorpus) {
0497     responseCorpus = aResponseCorpus;
0498   //setResponseCorpus
0499 
0500   /**
0501     @param anAnnotationSchema the annotation type being compared.
0502     * This type is found in annotationSchema object as field
0503     {@link gate.creole.AnnotationSchema#getAnnotationName()}. If is <b>null<b>
0504     * then AnnotDiff will throw an exception when it comes to do the diff.
0505     */
0506   public void setAnnotationSchema(AnnotationSchema anAnnotationSchema) {
0507     annotationSchema = anAnnotationSchema;
0508   // setAnnotationType
0509 
0510   /** @return the annotation schema object used in annotation diff process */
0511   public AnnotationSchema getAnnotationSchema(){
0512     return annotationSchema;
0513   // AnnotationSchema
0514 
0515   @Override
0516   public Dimension getPreferredScrollableViewportSize() {
0517         return getPreferredSize();
0518   }// public Dimension getPreferredScrollableViewportSize()
0519 
0520   @Override
0521   public int getScrollableUnitIncrement(Rectangle visibleRect,
0522                                               int orientation, int direction) {
0523     return maxUnitIncrement;
0524   }// public int getScrollableUnitIncrement
0525 
0526   @Override
0527   public int getScrollableBlockIncrement(Rectangle visibleRect,
0528                                               int orientation, int direction) {
0529     if (orientation == SwingConstants.HORIZONTAL)
0530         return visibleRect.width - maxUnitIncrement;
0531     else
0532         return visibleRect.height - maxUnitIncrement;
0533   }// public int getScrollableBlockIncrement
0534 
0535   @Override
0536   public boolean getScrollableTracksViewportWidth() {
0537     return false;
0538   }// public boolean getScrollableTracksViewportWidth()
0539 
0540   @Override
0541   public boolean getScrollableTracksViewportHeight() {
0542     return false;
0543   }
0544 
0545   /**
0546     * This method does the diff, Precision,Recall,FalsePositive
0547     * calculation and so on.
0548     */
0549   @Override
0550   public Resource init() throws ResourceInstantiationException {
0551     colors[DEFAULT_TYPE= WHITE;
0552     colors[CORRECT_TYPE= GREEN;
0553     colors[SPURIOUS_TYPE= RED;
0554     colors[PARTIALLY_CORRECT_TYPE= BLUE;
0555     colors[MISSING_TYPE= YELLOW;
0556 
0557     // Initialize the partially sets...
0558     keyPartiallySet = new HashSet<Annotation>();
0559     responsePartiallySet = new HashSet<Annotation>();
0560 
0561     // Do the diff, P&R calculation and so on
0562     AnnotationSet keyAnnotSet = null;
0563     AnnotationSet responseAnnotSet = null;
0564 
0565     if(annotationSchema == null)
0566      throw new ResourceInstantiationException("No annotation schema defined !");
0567 
0568     if(keyCorpus == null || == keyCorpus.size())
0569       throw new ResourceInstantiationException("No key corpus or empty defined !");
0570 
0571     if(responseCorpus == null || == responseCorpus.size())
0572       throw new ResourceInstantiationException("No response corpus or empty defined !");
0573 
0574     // init counters and do difference for documents by pairs
0575     for (int type=0; type < MAX_TYPES; type++)
0576       typeCounter[type0;
0577     diffSet = new HashSet<DiffSetElement>();
0578 
0579     for(int i=0; i<keyCorpus.size(); ++i) {
0580       keyDocument = keyCorpus.get(i);
0581       // find corresponding responce document if any
0582 
0583       Document doc;
0584       responseDocument = null;
0585       for(int j=0; j<responseCorpus.size(); ++j) {
0586         doc = responseCorpus.get(j);
0587         if(== doc.getName().compareTo(keyDocument.getName())
0588             || == doc.getSourceUrl().getFile().compareTo(
0589                       keyDocument.getSourceUrl().getFile())) {
0590           responseDocument = doc;
0591           break// response corpus loop
0592         // if
0593       // for
0594       
0595       if(null == responseDocument) {
0596         Out.prln("There is no mach in responce corpus for document '"
0597                   +keyDocument.getName()+"' from key corpus");
0598         continue// key corpus loop
0599       // if
0600       
0601       if (keyAnnotationSetName == null) {
0602         // Get the default key AnnotationSet from the keyDocument
0603         keyAnnotSet =  keyDocument.getAnnotations().get(
0604                                 annotationSchema.getAnnotationName());
0605       }
0606       else {
0607         keyAnnotSet =  keyDocument.getAnnotations(keyAnnotationSetName).get(
0608                                 annotationSchema.getAnnotationName());
0609       // if
0610   
0611       if (keyAnnotSet == null)
0612         // The diff will run with an empty set.All annotations from response
0613         // would be spurious.
0614         keyAnnotList = new LinkedList<Annotation>();
0615       else
0616         // The alghoritm will modify this annotation set. It is better to make a
0617         // separate copy of them.
0618         keyAnnotList = new LinkedList<Annotation>(keyAnnotSet);
0619   
0620       if (responseAnnotationSetName == null)
0621         // Get the response AnnotationSet from the default set
0622         responseAnnotSet = responseDocument.getAnnotations().get(
0623                                             annotationSchema.getAnnotationName());
0624       else
0625         responseAnnotSet = responseDocument.getAnnotations(responseAnnotationSetName).
0626                                       get(annotationSchema.getAnnotationName());
0627   
0628       if (responseAnnotSet == null)
0629         // The diff will run with an empty set.All annotations from key
0630         // would be missing.
0631         responseAnnotList = new LinkedList<Annotation>();
0632       else
0633         // The alghoritm will modify this annotation set. It is better to make a
0634         // separate copy of them.
0635         responseAnnotList = new LinkedList<Annotation>(responseAnnotSet);
0636   
0637       // Sort them ascending on Start offset (the comparator does that)
0638       AnnotationSetComparator asComparator = new AnnotationSetComparator();
0639       Collections.sort(keyAnnotList, asComparator);
0640       Collections.sort(responseAnnotList, asComparator);
0641   
0642       // Calculate the diff Set. This set will be used later with graphic
0643       // visualisation.
0644       doDiff(keyAnnotList, responseAnnotList);
0645     // for
0646     
0647     // If it runs under text mode just stop here.
0648     if (textModereturn this;
0649 
0650     //Show it
0651     // Configuring the formatter object. It will be used later to format
0652     // precision and recall
0653     formatter.setMaximumIntegerDigits(1);
0654     formatter.setMinimumFractionDigits(4);
0655     formatter.setMinimumFractionDigits(4);
0656 
0657     // Create an Annotation diff table model
0658     AnnotationDiffTableModel diffModel = new AnnotationDiffTableModel(diffSet);
0659     // Create a XJTable based on this model
0660     diffTable = new XJTable(diffModel);
0661     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
0662     // Set the cell renderer for this table.
0663     AnnotationDiffCellRenderer cellRenderer = new AnnotationDiffCellRenderer();
0664     diffTable.setDefaultRenderer(java.lang.String.class,cellRenderer);
0665     diffTable.setDefaultRenderer(java.lang.Long.class,cellRenderer);
0666     // Put the table into a JScroll
0667 
0668     // Arange all components on a this JPanel
0669     SwingUtilities.invokeLater(new Runnable(){
0670       @Override
0671       public void run(){
0672         arangeAllComponents();
0673       }
0674     });
0675 
0676     if (DEBUG)
0677       printStructure(diffSet);
0678 
0679     return this;
0680   //init()
0681 
0682   /** This method creates the graphic components and aranges them on
0683     <b>this</b> JPanel
0684     */
0685   protected void arangeAllComponents(){
0686     this.removeAll();
0687     // Setting the box layout for diffpanel
0688     BoxLayout boxLayout = new BoxLayout(this,BoxLayout.Y_AXIS);
0689     this.setLayout(boxLayout);
0690 
0691     JTableHeader tableHeader = diffTable.getTableHeader();
0692     tableHeader.setAlignmentX(Component.LEFT_ALIGNMENT);
0693     this.add(tableHeader);
0694     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
0695     // Add the tableScroll to the diffPanel
0696     this.add(diffTable);
0697 
0698 
0699     // ADD the LEGEND
0700     //Lay out the JLabels from left to right.
0701     //Box infoBox = new Box(BoxLayout.X_AXIS);
0702     JPanel infoBox = new  JPanel();
0703     infoBox.setLayout(new BoxLayout(infoBox,BoxLayout.X_AXIS));
0704     infoBox.setAlignmentX(Component.LEFT_ALIGNMENT);
0705     // Keep the components together
0706     //box.add(Box.createHorizontalGlue());
0707 
0708     Box box = new Box(BoxLayout.Y_AXIS);
0709     JLabel jLabel = new JLabel("LEGEND");
0710     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0711     jLabel.setOpaque(true);
0712     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0713     box.add(jLabel);
0714 
0715     jLabel = new JLabel("Missing (present in Key but not in Response):  " +
0716                                                 typeCounter[MISSING_TYPE]);
0717     jLabel.setForeground(BLACK);
0718     jLabel.setBackground(colors[MISSING_TYPE]);
0719     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0720     jLabel.setOpaque(true);
0721     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0722     box.add(jLabel);
0723 
0724     // Add a space
0725     box.add(Box.createRigidArea(new Dimension(0,5)));
0726 
0727     jLabel = new JLabel("Correct (total match):  " + typeCounter[CORRECT_TYPE]);
0728     jLabel.setForeground(BLACK);
0729     jLabel.setBackground(colors[CORRECT_TYPE]);
0730     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0731     jLabel.setOpaque(true);
0732     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0733     box.add(jLabel);
0734 
0735     // Add a space
0736     box.add(Box.createRigidArea(new Dimension(0,5)));
0737 
0738     jLabel =new JLabel("Partially correct (overlap in Key and Response):  "+
0739                                         typeCounter[PARTIALLY_CORRECT_TYPE]);
0740     jLabel.setForeground(BLACK);
0741     jLabel.setBackground(colors[PARTIALLY_CORRECT_TYPE]);
0742     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0743     jLabel.setOpaque(true);
0744     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0745     box.add(jLabel);
0746 
0747     // Add a space
0748     box.add(Box.createRigidArea(new Dimension(0,5)));
0749 
0750     jLabel = new JLabel("Spurious (present in Response but not in Key):  " +
0751                                         typeCounter[SPURIOUS_TYPE]);
0752     jLabel.setForeground(BLACK);
0753     jLabel.setBackground(colors[SPURIOUS_TYPE]);
0754     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0755     jLabel.setOpaque(true);
0756     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0757     box.add(jLabel);
0758 
0759     infoBox.add(box);
0760     // Add a space
0761     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0762 
0763     // Precision measure
0764     //Lay out the JLabels from left to right.
0765     box = new Box(BoxLayout.Y_AXIS);
0766 
0767     jLabel = new JLabel("Precision strict: " +
0768                                     formatter.format(precisionStrict));
0769     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0770     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0771     box.add(jLabel);
0772 
0773     jLabel = new JLabel("Precision average: " +
0774                                     formatter.format(precisionAverage));
0775     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0776     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0777     box.add(jLabel);
0778 
0779     jLabel = new JLabel("Precision lenient: " +
0780                                     formatter.format(precisionLenient));
0781     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0782     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0783     box.add(jLabel);
0784 
0785     infoBox.add(box);
0786     // Add a space
0787     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0788 
0789     // RECALL measure
0790     //Lay out the JLabels from left to right.
0791     box = new Box(BoxLayout.Y_AXIS);
0792 
0793     jLabel = new JLabel("Recall strict: " + formatter.format(recallStrict));
0794     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0795     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0796     box.add(jLabel);
0797 
0798     jLabel = new JLabel("Recall average: " + formatter.format(recallAverage));
0799     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0800     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0801     box.add(jLabel);
0802 
0803     jLabel = new JLabel("Recall lenient: " + formatter.format(recallLenient));
0804     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0805     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0806     box.add(jLabel);
0807 
0808     infoBox.add(box);
0809     // Add a space
0810     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0811 
0812     // F-Measure
0813     //Lay out the JLabels from left to right.
0814     box = new Box(BoxLayout.Y_AXIS);
0815 
0816     jLabel = new JLabel("F-Measure strict: " +
0817                                         formatter.format(fMeasureStrict));
0818     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0819     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0820     box.add(jLabel);
0821 
0822     jLabel = new JLabel("F-Measure average: " +
0823                                         formatter.format(fMeasureAverage));
0824     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0825     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0826     box.add(jLabel);
0827 
0828     jLabel = new JLabel("F-Measure lenient: " +
0829                                         formatter.format(fMeasureLenient));
0830     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0831     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0832     box.add(jLabel);
0833     infoBox.add(box);
0834 
0835     // Add a space
0836     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0837 
0838     // FALSE POZITIVE measure
0839     //Lay out the JLabels from left to right.
0840     box = new Box(BoxLayout.Y_AXIS);
0841 
0842     jLabel = new JLabel("False positive strict: " +
0843                                         formatter.format(falsePositiveStrict));
0844     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0845     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0846     box.add(jLabel);
0847 
0848     jLabel = new JLabel("False positive average: " +
0849                                         formatter.format(falsePositiveAverage));
0850     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0851     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0852     box.add(jLabel);
0853 
0854     jLabel = new JLabel("False positive lenient: " +
0855                                         formatter.format(falsePositiveLenient));
0856     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0857     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0858     box.add(jLabel);
0859     infoBox.add(box);
0860 
0861     // Add a space
0862     infoBox.add(Box.createRigidArea(new Dimension(10,0)));
0863 
0864     this.add(infoBox);
0865   //arangeAllComponents
0866 
0867   /** Used internally for debugging */
0868   protected void printStructure(Set<DiffSetElement> aDiffSet){
0869     Iterator<DiffSetElement> iterator = aDiffSet.iterator();
0870     String leftAnnot = null;
0871     String rightAnnot = null;
0872     while(iterator.hasNext()){
0873       DiffSetElement diffElem = iterator.next();
0874       if (diffElem.getLeftAnnotation() == null)
0875         leftAnnot = "NULL ";
0876       else
0877         leftAnnot = diffElem.getLeftAnnotation().toString();
0878       if (diffElem.getRightAnnotation() == null)
0879         rightAnnot = " NULL";
0880       else
0881         rightAnnot = diffElem.getRightAnnotation().toString();
0882       Out.prlnleftAnnot + "|" + rightAnnot);
0883     // end while
0884   // printStructure
0885 
0886   /** This method is the brain of the AnnotationSet diff and creates a set with
0887     * diffSetElement objects.
0888     @param aKeyAnnotList a list containing the annotations from key. If this
0889     * param is <b>null</b> then the method will simply return and will not do a
0890     * thing.
0891     @param aResponseAnnotList a list containing the annotation from response.
0892     * If this param is <b>null</b> the method will return.
0893     */
0894   protected void doDiff(List<Annotation> aKeyAnnotList,
0895                         List<Annotation> aResponseAnnotList){
0896 
0897     // If one of the annotation sets is null then is no point in doing the diff.
0898     if (aKeyAnnotList == null || aResponseAnnotList == null)
0899       return;
0900 
0901     // Iterate throught all elements from keyList and find those in the response
0902     // list which satisfies isCompatible() and isPartiallyCompatible() relations
0903     Iterator<Annotation> keyIterator = aKeyAnnotList.iterator();
0904     while(keyIterator.hasNext()){
0905       Annotation keyAnnot = keyIterator.next();
0906       Iterator<Annotation> responseIterator = aResponseAnnotList.iterator();
0907 
0908       DiffSetElement diffElement = null;
0909       while(responseIterator.hasNext()){
0910         Annotation responseAnnot = responseIterator.next();
0911 
0912         if(keyAnnot.isPartiallyCompatible(responseAnnot,keyFeatureNamesSet)){
0913           keyPartiallySet.add(keyAnnot);
0914           responsePartiallySet.add(responseAnnot);
0915           if (keyAnnot.coextensive(responseAnnot)){
0916             // Found two compatible annotations
0917             // Create a new DiffSetElement and add it to the diffSet
0918             diffElement = new DiffSetElementkeyAnnot,
0919                                               responseAnnot,
0920                                               DEFAULT_TYPE,
0921                                               CORRECT_TYPE,
0922                                               keyDocument,
0923                                               responseDocument);
0924 
0925             // Add this element to the DiffSet
0926             addToDiffset(diffElement);
0927           // End if (keyAnnot.coextensive(responseAnnot))
0928         }else if (keyAnnot.coextensive(responseAnnot)){
0929           // Found two aligned annotations. We have to find out if the response
0930           // is partialy compatible with another key annotation.
0931           // Create a new DiffSetElement and add it to the diffSet
0932           diffElement = new DiffSetElementkeyAnnot,
0933                                             responseAnnot,
0934                                             detectKeyType(keyAnnot),
0935                                             detectResponseType(responseAnnot),
0936                                             keyDocument,
0937                                             responseDocument);
0938           // Add this element to the DiffSet
0939           addToDiffset(diffElement);
0940         // End if (keyAnnot.coextensive(responseAnnot)){
0941 
0942         if (diffElement != null){
0943           // Eliminate the response annotation from the list.
0944           responseIterator.remove();
0945           break;
0946         // End if
0947       // end while responseIterator
0948 
0949       // If diffElement != null it means that break was used
0950       if (diffElement == null){
0951         if (keyPartiallySet.contains(keyAnnot))
0952           diffElement = new DiffSetElementkeyAnnot,
0953                                             null,
0954                                             DEFAULT_TYPE,
0955                                             NULL_TYPE,
0956                                             keyDocument,
0957                                             responseDocument);
0958         else{
0959           // If keyAnnot is not in keyPartiallySet then it has to be checked
0960           // agains all annotations in DiffSet to see if there is
0961           // a previous annotation from response set which is partially
0962           // compatible with the keyAnnot
0963           Iterator<DiffSetElement> respParIter = diffSet.iterator();
0964           while (respParIter.hasNext()){
0965             DiffSetElement diffElem = respParIter.next();
0966             Annotation respAnnot = diffElem.getRightAnnotation();
0967             if (respAnnot != null && keyAnnot.isPartiallyCompatible(respAnnot,
0968                                                           keyFeatureNamesSet)){
0969                 diffElement = new DiffSetElementkeyAnnot,
0970                                                   null,
0971                                                   DEFAULT_TYPE,
0972                                                   NULL_TYPE,
0973                                                   keyDocument,
0974                                                   responseDocument);
0975                 break;
0976             // End if
0977           // End while
0978           // If is still nul then it means that the key annotation is missing
0979           if (diffElement == null)
0980             diffElement = new DiffSetElementkeyAnnot,
0981                                               null,
0982                                               MISSING_TYPE,
0983                                               NULL_TYPE,
0984                                               keyDocument,
0985                                               responseDocument);
0986         // End if
0987         addToDiffset(diffElement);
0988       // End if
0989 
0990       keyIterator.remove();
0991     // end while keyIterator
0992 
0993     DiffSetElement diffElem = null;
0994     Iterator<Annotation> responseIter = aResponseAnnotList.iterator();
0995     while (responseIter.hasNext()){
0996       Annotation respAnnot = responseIter.next();
0997       if (responsePartiallySet.contains(respAnnot))
0998         diffElem = new DiffSetElementnull,
0999                                        respAnnot,
1000                                        NULL_TYPE,
1001                                        PARTIALLY_CORRECT_TYPE,
1002                                        keyDocument,
1003                                        responseDocument);
1004       else
1005         diffElem = new DiffSetElementnull,
1006                                        respAnnot,
1007                                        NULL_TYPE,
1008                                        SPURIOUS_TYPE,
1009                                        keyDocument,
1010                                        responseDocument);
1011       addToDiffset(diffElem);
1012       responseIter.remove();
1013     // End while
1014 
1015     // CALCULATE ALL (NLP) MEASURES like:
1016     // Precistion, Recall, FalsePositive and F-Measure
1017     int possible =  typeCounter[CORRECT_TYPE+  // this comes from Key or Resp
1018                     typeCounter[PARTIALLY_CORRECT_TYPE// this comes from Resp
1019                     typeCounter[MISSING_TYPE]// this comes from Key
1020 
1021     int actual =  typeCounter[CORRECT_TYPE+  // this comes from Key or Resp
1022                   typeCounter[PARTIALLY_CORRECT_TYPE// this comes from Resp
1023                   typeCounter[SPURIOUS_TYPE]// this comes from Resp
1024 /*
1025     if (actual != responseSize)
1026       Err.prln("AnnotDiff warning: The response size(" + responseSize +
1027       ") is not the same as the computed value of" +
1028     " actual(Correct[resp or key]+Partial[resp]+Spurious[resp]=" + actual +")");
1029 */
1030     if (actual != 0){
1031       precisionStrict =  ((double)typeCounter[CORRECT_TYPE])/((double)actual);
1032       precisionLenient = ((double)(typeCounter[CORRECT_TYPE+
1033                          typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)actual);
1034       precisionAverage = (precisionStrict + precisionLenient/
1035                                                                   2;
1036     // End if
1037     if (possible != 0){
1038       recallStrict = ((double)typeCounter[CORRECT_TYPE])/((double)possible);
1039       recallLenient = ((double)(typeCounter[CORRECT_TYPE+
1040                        typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)possible);
1041       recallAverage = (recallStrict + recallLenient2;
1042     // End if
1043 
1044 
1045     int no = 0;
1046     // If an annotation type for false poz was selected calculate the number of
1047     // Annotations
1048     if (annotationTypeForFalsePositive != null)
1049      // Was it the default set ?
1050      if (responseAnnotationSetNameFalsePoz == null){
1051       AnnotationSet aSet = responseDocument.getAnnotations().get(
1052                                       annotationTypeForFalsePositive);
1053           no = aSet == null : aSet.size();
1054      }else{
1055       AnnotationSet aSet = responseDocument.getAnnotations(responseAnnotationSetNameFalsePoz).get(
1056                                         annotationTypeForFalsePositive);
1057       no = aSet == null: aSet.size();
1058      }
1059     if (no != 0){
1060       // No error here: the formula is the opposite to recall or precission
1061      falsePositiveStrict = ((double)(typeCounter[SPURIOUS_TYPE+
1062                              typeCounter[PARTIALLY_CORRECT_TYPE])) /((double)no);
1063      falsePositiveLenient = ((double)typeCounter[SPURIOUS_TYPE]) /((doubleno);
1064      falsePositiveAverage = (falsePositiveStrict +
1065                                            falsePositiveLenient)/;
1066     // End if
1067 
1068     // Calculate F-Measure Strict
1069     double denominator = weight * (precisionStrict + recallStrict);
1070     if (denominator != 0)
1071       fMeasureStrict = (precisionStrict * recallStrict/ denominator ;
1072     else fMeasureStrict = 0.0;
1073     // Calculate F-Measure Lenient
1074     denominator = weight * (precisionLenient + recallLenient);
1075     if (denominator != 0)
1076       fMeasureLenient = (precisionLenient * recallLenient/ denominator ;
1077     else fMeasureLenient = 0.0;
1078     // Calculate F-Measure Average
1079     fMeasureAverage = (fMeasureStrict + fMeasureLenient2;
1080 
1081   // doDiff
1082 
1083   /** Decide what type is the keyAnnotation (DEFAULT_TYPE, MISSING or NULL_TYPE)
1084    *  This method must be applied only on annotation from key set.
1085    *  @param anAnnot is an annotation from the key set.
1086    *  @return three possible value(DEFAULT_TYPE, MISSING or NULL_TYPE)
1087    */
1088   private int detectKeyType(Annotation anAnnot){
1089     if (anAnnot == nullreturn NULL_TYPE;
1090 
1091     if (keyPartiallySet.contains(anAnnot)) return DEFAULT_TYPE;
1092     Iterator<Annotation> iter = responsePartiallySet.iterator();
1093     while(iter.hasNext()){
1094       Annotation a = iter.next();
1095       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet))
1096         return DEFAULT_TYPE;
1097     // End while
1098 
1099     iter = responseAnnotList.iterator();
1100     while(iter.hasNext()){
1101       Annotation a = iter.next();
1102       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet)){
1103          responsePartiallySet.add(a);
1104          keyPartiallySet.add(anAnnot);
1105          return DEFAULT_TYPE;
1106       // End if
1107     // End while
1108     return MISSING_TYPE;
1109   //detectKeyType
1110 
1111   /**  Decide what type is the responseAnnotation
1112     *  (PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
1113     *  This method must be applied only on annotation from response set.
1114     *  @param anAnnot is an annotation from the key set.
1115     *  @return three possible value(PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
1116     */
1117   private int detectResponseType(Annotation anAnnot){
1118     if (anAnnot == nullreturn NULL_TYPE;
1119 
1120     if (responsePartiallySet.contains(anAnnot)) return PARTIALLY_CORRECT_TYPE;
1121     Iterator<Annotation> iter = keyPartiallySet.iterator();
1122     while(iter.hasNext()){
1123       Annotation a = iter.next();
1124       if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet))
1125         return PARTIALLY_CORRECT_TYPE;
1126     // End while
1127 
1128     iter = keyAnnotList.iterator();
1129     while(iter.hasNext()){
1130       Annotation a = iter.next();
1131       if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet)){
1132          responsePartiallySet.add(anAnnot);
1133          keyPartiallySet.add(a);
1134          return PARTIALLY_CORRECT_TYPE;
1135       // End if
1136     // End while
1137     return SPURIOUS_TYPE;
1138   //detectResponseType
1139 
1140   /** This method add an DiffsetElement to the DiffSet and also counts the
1141     * number of compatible, partialCompatible, Incorect and Missing annotations.
1142     */
1143   private void addToDiffset(DiffSetElement aDiffSetElement){
1144     if (aDiffSetElement == nullreturn;
1145 
1146     diffSet.add(aDiffSetElement);
1147     // For the Right side (response) the type can be one of the following:
1148     // PC, I, C
1149     if (NULL_TYPE != aDiffSetElement.getRightType())
1150       typeCounter[aDiffSetElement.getRightType()]++;
1151     // For the left side (key) the type can be : D or M
1152     if (NULL_TYPE != aDiffSetElement.getLeftType() &&
1153         CORRECT_TYPE != aDiffSetElement.getLeftType())
1154       typeCounter[aDiffSetElement.getLeftType()]++;
1155   // addToDiffset
1156 
1157   /* ********************************************************************
1158    * INNER CLASS
1159    * ********************************************************************/
1160 
1161   /**
1162     * A custom table model used to render a table containing the two annotation
1163     * sets. The columns will be:
1164     * (KEY) Type, Start, End, Features, empty column,(Response) Type,Start, End, Features
1165     */
1166   protected class AnnotationDiffTableModel extends AbstractTableModel{
1167 
1168     private static final long serialVersionUID = 1410683181803904176L;
1169 
1170     /** Constructs an AnnotationDiffTableModel given a data Collection */
1171     public AnnotationDiffTableModel(Collection<DiffSetElement> data){
1172       modelData = new ArrayList<DiffSetElement>();
1173       modelData.addAll(data);
1174     // AnnotationDiffTableModel
1175 
1176     /** Constructs an AnnotationDiffTableModel */
1177     public AnnotationDiffTableModel(){
1178       modelData = new ArrayList<DiffSetElement>();
1179     // AnnotationDiffTableModel
1180 
1181     /** Return the size of data.*/
1182     @Override
1183     public int getRowCount(){
1184       return modelData.size();
1185     //getRowCount
1186 
1187     /** Return the number of columns.*/
1188     @Override
1189     public int getColumnCount(){
1190       return 10;
1191     //getColumnCount
1192 
1193     /** Returns the name of each column in the model*/
1194     @Override
1195     public String getColumnName(int column){
1196       switch(column){
1197         case 0return "String - Key";
1198         case 1return "Start - Key";
1199         case 2return "End - Key";
1200         case 3return "Features - Key";
1201         case 4return "   ";
1202         case 5return "String - Response";
1203         case 6return "Start - Response";
1204         case 7return "End -Response";
1205         case 8return "Features - Response";
1206         case 9return "Document";
1207         default:return "?";
1208       }
1209     //getColumnName
1210 
1211     /** Return the class type for each column. */
1212     @Override
1213     public Class<?> getColumnClass(int column){
1214       switch(column){
1215         case 0return String.class;
1216         case 1return Long.class;
1217         case 2return Long.class;
1218         case 3return String.class;
1219         case 4return String.class;
1220         case 5return String.class;
1221         case 6return Long.class;
1222         case 7return Long.class;
1223         case 8return String.class;
1224         case 9return String.class;
1225         default:return Object.class;
1226       }
1227     //getColumnClass
1228 
1229     /**Returns a value from the table model */
1230     @Override
1231     public Object getValueAt(int row, int column){
1232       DiffSetElement diffSetElement = modelData.get(row);
1233       if (diffSetElement == nullreturn null;
1234       switch(column){
1235         // Left Side (Key)
1236         //Type - Key
1237         case 0:{
1238            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1239 //           return diffSetElement.getLeftAnnotation().getType();
1240            Annotation annot = diffSetElement.getLeftAnnotation();
1241            String theString = "";
1242            try {
1243              theString = diffSetElement.getKeyDocument().getContent().getContent(
1244                     annot.getStartNode().getOffset(),
1245                     annot.getEndNode().getOffset()).toString();
1246            catch (gate.util.InvalidOffsetException ex) {
1247              Err.prln(ex.getMessage());
1248            }
1249            return theString;
1250         }
1251         // Start - Key
1252         case 1:{
1253            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1254            return diffSetElement.getLeftAnnotation().getStartNode().getOffset();
1255         }
1256         // End - Key
1257         case 2:{
1258            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1259            return diffSetElement.getLeftAnnotation().getEndNode().getOffset();
1260         }
1261         // Features - Key
1262         case 3:{
1263            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1264            if (diffSetElement.getLeftAnnotation().getFeatures() == null)
1265              return null;
1266            return diffSetElement.getLeftAnnotation().getFeatures().toString();
1267         }
1268         // Empty column
1269         case 4:{
1270           return "   ";
1271         }
1272         // Right Side (Response)
1273         //Type - Response
1274         case 5:{
1275            if (diffSetElement.getRightAnnotation() == nullreturn null;
1276 //           return diffSetElement.getRightAnnotation().getType();
1277            Annotation annot = diffSetElement.getRightAnnotation();
1278            String theString = "";
1279            try {
1280              theString = diffSetElement.getResponseDocument().getContent().getContent(
1281                     annot.getStartNode().getOffset(),
1282                     annot.getEndNode().getOffset()).toString();
1283            catch (gate.util.InvalidOffsetException ex) {
1284              Err.prln(ex.getMessage());
1285            }
1286            return theString;
1287         }
1288         // Start - Response
1289         case 6:{
1290            if (diffSetElement.getRightAnnotation() == nullreturn null;
1291           return diffSetElement.getRightAnnotation().getStartNode().getOffset();
1292         }
1293         // End - Response
1294         case 7:{
1295            if (diffSetElement.getRightAnnotation() == nullreturn null;
1296            return diffSetElement.getRightAnnotation().getEndNode().getOffset();
1297         }
1298         // Features - resonse
1299         case 8:{
1300            if (diffSetElement.getRightAnnotation() == nullreturn null;
1301            return diffSetElement.getRightAnnotation().getFeatures().toString();
1302         }
1303         // Document name
1304         case 9:{
1305           return diffSetElement.getKeyDocument().getName();
1306         }
1307         // The hidden column
1308         case 10:{
1309           return diffSetElement;
1310         }
1311         default:{return null;}
1312       // End switch
1313     //getValueAt
1314 
1315     public Object getRawObject(int row){
1316       return modelData.get(row);
1317     //getRawObject
1318 
1319     /** Holds the data for TableDiff*/
1320     private List<DiffSetElement> modelData = null;
1321 
1322   //Inner class AnnotationDiffTableModel
1323 
1324   /* ********************************************************************
1325    * INNER CLASS
1326    * ********************************************************************/
1327   /**
1328     * This class defines a Cell renderer for the AnnotationDiff table
1329     */
1330   public class AnnotationDiffCellRenderer extends DefaultTableCellRenderer{
1331 
1332     private static final long serialVersionUID = -7804261826021343001L;
1333 
1334     /** Constructs a randerer with a table model*/
1335     public AnnotationDiffCellRenderer() { }  //AnnotationDiffCellRenderer
1336 
1337     private Color background = WHITE;
1338 
1339     /** This method is called by JTable*/
1340 
1341     @Override
1342     public Component getTableCellRendererComponent(
1343       JTable table, Object value, boolean isSelected, boolean hasFocus,
1344       int row, int column
1345     ) {
1346       JComponent defaultComp = null;
1347       defaultComp = (JComponentsuper.getTableCellRendererComponent(
1348   table, value, isSelected, hasFocus, row, column
1349       );
1350 
1351       // The column number four will be randered using a blank component
1352       if (column == || value == null)
1353         return new JPanel();
1354 
1355       if (!(table.getModel().getValueAt(row,10instanceof DiffSetElement))
1356         return defaultComp;
1357 
1358       DiffSetElement diffSetElement =
1359                         (DiffSetElementtable.getModel().getValueAt(row,10);
1360 
1361       if (diffSetElement == null)
1362         return defaultComp;
1363 
1364       if (column < 4){
1365         if (NULL_TYPE != diffSetElement.getLeftType())
1366           background = colors[diffSetElement.getLeftType()];
1367         else return new JPanel();
1368       }else if (column < 10){
1369         if (NULL_TYPE != diffSetElement.getRightType())
1370           background = colors[diffSetElement.getRightType()];
1371         else return new JPanel();
1372       }
1373 
1374       defaultComp.setBackground(background);
1375       defaultComp.setForeground(BLACK);
1376 
1377       defaultComp.setOpaque(true);
1378       return defaultComp;
1379     //getTableCellRendererComponent
1380 
1381   // class AnnotationDiffCellRenderer
1382 
1383   /* ********************************************************************
1384    * INNER CLASS
1385    * ********************************************************************/
1386    class AnnotationSetComparator implements Comparator<Annotation> {
1387 
1388       public AnnotationSetComparator(){}
1389 
1390       @Override
1391       public int compare(Annotation a1, Annotation a2) {
1392         
1393         Long l1 = a1.getStartNode().getOffset();
1394         Long l2 = a2.getStartNode().getOffset();
1395         if (l1 != null)
1396           return l1.compareTo(l2);
1397         else
1398           return -1;
1399       //compare
1400     // class AnnotationSetComparator
1401 
1402   /* ********************************************************************
1403    * INNER CLASS
1404    * ********************************************************************/
1405 
1406   /**
1407     * This class is used for internal purposes. It represents a row from the
1408     * table.
1409     */
1410   protected class DiffSetElement {
1411     /** This field represent a key annotation*/
1412     private Annotation leftAnnotation = null;
1413     /** This field represent a response annotation*/
1414     private Annotation rightAnnotation = null;
1415     /** Default initialization of the key type*/
1416     private int leftType = DEFAULT_TYPE;
1417     /** Default initialization of the response type*/
1418     private int rightType = DEFAULT_TYPE;
1419     /** Key document */
1420     private Document keyDocument;
1421     /** Response document */
1422     private Document respDocument;
1423 
1424     /** Constructor for DiffSetlement*/
1425     public DiffSetElement() {}
1426 
1427     /** Constructor for DiffSetlement*/
1428     public DiffSetElementAnnotation aLeftAnnotation,
1429                            Annotation aRightAnnotation,
1430                            int aLeftType,
1431                            int aRightType){
1432       leftAnnotation = aLeftAnnotation;
1433       rightAnnotation = aRightAnnotation;
1434       leftType = aLeftType;
1435       rightType = aRightType;
1436       keyDocument = null;
1437       respDocument = null;
1438     // DiffSetElement
1439 
1440     /** Constructor for DiffSetlement with document name */
1441     public DiffSetElementAnnotation aLeftAnnotation,
1442                            Annotation aRightAnnotation,
1443                            int aLeftType,
1444                            int aRightType,
1445                            Document kDocument,
1446                            Document rDocument){
1447       leftAnnotation = aLeftAnnotation;
1448       rightAnnotation = aRightAnnotation;
1449       leftType = aLeftType;
1450       rightType = aRightType;
1451       keyDocument = kDocument;
1452       respDocument = rDocument;
1453     // DiffSetElement
1454     
1455     /** Sets the left annotation*/
1456     public void setLeftAnnotation(Annotation aLeftAnnotation){
1457       leftAnnotation = aLeftAnnotation;
1458     // setLeftAnnot
1459 
1460     /** Gets the left annotation*/
1461     public Annotation getLeftAnnotation(){
1462       return leftAnnotation;
1463     // getLeftAnnotation
1464 
1465     /** Sets the right annotation*/
1466     public void setRightAnnotation(Annotation aRightAnnotation){
1467       rightAnnotation = aRightAnnotation;
1468     // setRightAnnot
1469 
1470     /** Gets the right annotation*/
1471     public Annotation getRightAnnotation(){
1472       return rightAnnotation;
1473     // getRightAnnotation
1474 
1475     /** Sets the left type*/
1476     public void setLeftType(int aLeftType){
1477       leftType = aLeftType;
1478     // setLeftType
1479 
1480     /** Get the left type */
1481     public int getLeftType() {
1482       return leftType;
1483     // getLeftType
1484 
1485     /** Sets the right type*/
1486     public void setRightType(int aRightType) {
1487       rightType = aRightType;
1488     // setRightType
1489 
1490     /** Get the right type*/
1491     public int getRightType() {
1492       return rightType;
1493     // getRightType
1494 
1495     /** Get Key document */
1496     public Document getKeyDocument() {
1497       return keyDocument;
1498     // getKeyDocument
1499 
1500     /** Set Key document */
1501     public void setKeyDocument(Document aDoc) {
1502       keyDocument = aDoc;
1503     // setKeyDocument
1504 
1505     /** Get Response document */
1506     public Document getResponseDocument() {
1507       return respDocument;
1508     // getResponseDocument
1509 
1510     /** Set Response document */
1511     public void setResponseDocument(Document aDoc) {
1512       respDocument = aDoc;
1513     // setResponseDocument
1514   // classs DiffSetElement
1515 // class CorpusAnnotationDiff