Search in sources :

Example 1 with Configuration

use of de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration in project webanno by webanno.

the class AgreementUtils method dumpAgreementConfigurationSets.

private static void dumpAgreementConfigurationSets(PrintStream aOut, AgreementResult<ICodingAnnotationStudy> aAgreement, List<ConfigurationSet> aSets) {
    for (ConfigurationSet cfgSet : aSets) {
        StringBuilder sb = new StringBuilder();
        sb.append(cfgSet.getPosition());
        for (Configuration cfg : cfgSet.getConfigurations()) {
            if (sb.length() > 0) {
                sb.append(" \t");
            }
            sb.append(cfg.toString());
        }
        aOut.println(sb);
    }
}
Also used : ConfigurationSet(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet) Configuration(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration)

Example 2 with Configuration

use of de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration in project webanno by webanno.

the class SuggestionViewPanel method addSuggestionColor.

/**
 * For each {@link ConfigurationSet}, where there are some differences in users annotation and
 * the curation annotation.
 */
private void addSuggestionColor(Project aProject, Mode aMode, Map<String, CAS> aCasMap, Map<String, Map<VID, AnnotationState>> aSuggestionColors, Collection<ConfigurationSet> aCfgSet, boolean aDisagree, boolean aAgree) {
    for (ConfigurationSet cs : aCfgSet) {
        boolean use = false;
        for (String u : cs.getCasGroupIds()) {
            Map<VID, AnnotationState> colors = aSuggestionColors.computeIfAbsent(u, k -> new HashMap<>());
            for (Configuration c : cs.getConfigurations(u)) {
                FeatureStructure fs = c.getFs(u, aCasMap);
                AnnotationLayer layer = schemaService.findLayer(aProject, fs.getType().getName());
                TypeAdapter typeAdapter = schemaService.getAdapter(layer);
                VID vid;
                // link FS
                if (c.getPosition().getFeature() != null) {
                    int fi = 0;
                    for (AnnotationFeature f : typeAdapter.listFeatures()) {
                        if (f.getName().equals(c.getPosition().getFeature())) {
                            break;
                        }
                        fi++;
                    }
                    vid = new VID(WebAnnoCasUtil.getAddr(fs), fi, c.getAID(u).index);
                } else {
                    vid = new VID(WebAnnoCasUtil.getAddr(fs));
                }
                if (aAgree) {
                    colors.put(vid, AGREE);
                    continue;
                }
                // automation and correction projects
                if (!aMode.equals(CURATION) && !aAgree) {
                    if (cs.getCasGroupIds().size() == 2) {
                        colors.put(vid, DO_NOT_USE);
                    } else {
                        colors.put(vid, DISAGREE);
                    }
                    continue;
                }
                // this set agree with the curation annotation
                if (c.getCasGroupIds().contains(CURATION_USER)) {
                    use = true;
                } else {
                    use = false;
                }
                // this curation view
                if (u.equals(CURATION_USER)) {
                    continue;
                }
                if (aAgree) {
                    colors.put(vid, AGREE);
                } else if (use) {
                    colors.put(vid, USE);
                } else if (aDisagree) {
                    colors.put(vid, DISAGREE);
                } else if (!cs.getCasGroupIds().contains(CURATION_USER)) {
                    colors.put(vid, DISAGREE);
                } else {
                    colors.put(vid, DO_NOT_USE);
                }
            }
        }
    }
}
Also used : Configuration(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration) AnnotationLayer(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer) VID(de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.VID) FeatureStructure(org.apache.uima.cas.FeatureStructure) ConfigurationSet(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet) TypeAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.TypeAdapter) AnnotationState(de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.AnnotationState) AnnotationFeature(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature)

Example 3 with Configuration

use of de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration in project webanno by webanno.

the class AgreementUtils method makeCodingStudy.

private static CodingAgreementResult makeCodingStudy(CasDiff aDiff, Collection<String> aUsers, String aType, String aFeature, boolean aExcludeIncomplete, boolean aNullLabelsAsEmpty, Map<String, List<CAS>> aCasMap) {
    List<String> users = new ArrayList<>(aUsers);
    Collections.sort(users);
    List<ConfigurationSet> completeSets = new ArrayList<>();
    List<ConfigurationSet> setsWithDifferences = new ArrayList<>();
    List<ConfigurationSet> incompleteSetsByPosition = new ArrayList<>();
    List<ConfigurationSet> incompleteSetsByLabel = new ArrayList<>();
    List<ConfigurationSet> pluralitySets = new ArrayList<>();
    List<ConfigurationSet> irrelevantSets = new ArrayList<>();
    CodingAnnotationStudy study = new CodingAnnotationStudy(users.size());
    // Check if the feature we are looking at is a primitive feature or a link feature
    // We do this by looking it up in the first available CAS. Mind that at this point all
    // CASes should have exactly the same typesystem.
    CAS someCas = findSomeCas(aCasMap);
    if (someCas == null) {
        // Well... there is NOTHING here!
        // All positions are irrelevant
        aDiff.getPositions().forEach(p -> irrelevantSets.add(aDiff.getConfigurationSet(p)));
        return new CodingAgreementResult(aType, aFeature, aDiff.toResult(), study, users, completeSets, irrelevantSets, setsWithDifferences, incompleteSetsByPosition, incompleteSetsByLabel, pluralitySets, aExcludeIncomplete);
    }
    TypeSystem ts = someCas.getTypeSystem();
    // We should just do the right thing here which is: do nothing
    if (ts.getType(aType) == null) {
        // All positions are irrelevant
        aDiff.getPositions().forEach(p -> irrelevantSets.add(aDiff.getConfigurationSet(p)));
        return new CodingAgreementResult(aType, aFeature, aDiff.toResult(), study, users, completeSets, irrelevantSets, setsWithDifferences, incompleteSetsByPosition, incompleteSetsByLabel, pluralitySets, aExcludeIncomplete);
    }
    // Check that the feature really exists instead of just getting a NPE later
    if (ts.getType(aType).getFeatureByBaseName(aFeature) == null) {
        throw new IllegalArgumentException("Type [" + aType + "] has no feature called [" + aFeature + "]");
    }
    boolean isPrimitiveFeature = ts.getType(aType).getFeatureByBaseName(aFeature).getRange().isPrimitive();
    nextPosition: for (Position p : aDiff.getPositions()) {
        ConfigurationSet cfgSet = aDiff.getConfigurationSet(p);
        // Only calculate agreement for the given layer
        if (!cfgSet.getPosition().getType().equals(aType)) {
            // We don't even consider these as irrelevant, they are just filtered out
            continue;
        }
        // If the feature on a position is set, then it is a subposition
        boolean isSubPosition = p.getFeature() != null;
        // this is an inverted XOR!
        if (!(isPrimitiveFeature ^ isSubPosition)) {
            irrelevantSets.add(cfgSet);
            continue;
        }
        // feature
        if (isSubPosition && !aFeature.equals(cfgSet.getPosition().getFeature())) {
            irrelevantSets.add(cfgSet);
            continue nextPosition;
        }
        // If non of the current users has made any annotation at this position, then skip it
        if (users.stream().filter(u -> cfgSet.getCasGroupIds().contains(u)).count() == 0) {
            irrelevantSets.add(cfgSet);
            continue nextPosition;
        }
        Object[] values = new Object[users.size()];
        int i = 0;
        for (String user : users) {
            // this configuration set.
            if (!cfgSet.getCasGroupIds().contains(user)) {
                incompleteSetsByPosition.add(cfgSet);
                if (aExcludeIncomplete) {
                    // Record as incomplete
                    continue nextPosition;
                } else {
                    // Record as missing value
                    values[i] = null;
                    i++;
                    continue;
                }
            }
            // Make sure a single user didn't do multiple alternative annotations at a single
            // position. So there is currently no support for calculating agreement on stacking
            // annotations.
            List<Configuration> cfgs = cfgSet.getConfigurations(user);
            if (cfgs.size() > 1) {
                pluralitySets.add(cfgSet);
                continue nextPosition;
            }
            Configuration cfg = cfgs.get(0);
            // Check if source and/or targets of a relation are stacked
            if (cfg.getPosition() instanceof RelationPosition) {
                RelationPosition pos = (RelationPosition) cfg.getPosition();
                FeatureStructure arc = cfg.getFs(user, pos.getCasId(), aCasMap);
                RelationDiffAdapter adapter = (RelationDiffAdapter) aDiff.getTypeAdapters().get(pos.getType());
                // Check if the source of the relation is stacked
                AnnotationFS source = FSUtil.getFeature(arc, adapter.getSourceFeature(), AnnotationFS.class);
                List<AnnotationFS> sourceCandidates = CasUtil.selectAt(arc.getCAS(), source.getType(), source.getBegin(), source.getEnd());
                if (sourceCandidates.size() > 1) {
                    pluralitySets.add(cfgSet);
                    continue nextPosition;
                }
                // Check if the target of the relation is stacked
                AnnotationFS target = FSUtil.getFeature(arc, adapter.getTargetFeature(), AnnotationFS.class);
                List<AnnotationFS> targetCandidates = CasUtil.selectAt(arc.getCAS(), target.getType(), target.getBegin(), target.getEnd());
                if (targetCandidates.size() > 1) {
                    pluralitySets.add(cfgSet);
                    continue nextPosition;
                }
            }
            // Only calculate agreement for the given feature
            FeatureStructure fs = cfg.getFs(user, cfg.getPosition().getCasId(), aCasMap);
            values[i] = extractValueForAgreement(fs, aFeature, cfg.getAID(user).index, cfg.getPosition().getLinkCompareBehavior());
            // agreement calculation. The empty label is still a valid label.
            if (aNullLabelsAsEmpty && values[i] == null) {
                values[i] = "";
            }
            // "null" cannot be used in agreement calculations. We treat these as incomplete
            if (values[i] == null) {
                incompleteSetsByLabel.add(cfgSet);
                if (aExcludeIncomplete) {
                    continue nextPosition;
                }
            }
            i++;
        }
        if (ObjectUtils.notEqual(values[0], values[1])) {
            setsWithDifferences.add(cfgSet);
        }
        // are calculating agreement over
        assert cfgSet.getPosition().getFeature() == null || cfgSet.getPosition().getFeature().equals(aFeature);
        completeSets.add(cfgSet);
        study.addItemAsArray(values);
    }
    return new CodingAgreementResult(aType, aFeature, aDiff.toResult(), study, users, completeSets, irrelevantSets, setsWithDifferences, incompleteSetsByPosition, incompleteSetsByLabel, pluralitySets, aExcludeIncomplete);
}
Also used : LinkCompareBehavior(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.LinkCompareBehavior) WebAnnoCasUtil.getFeature(de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.getFeature) CasDiff(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) Configuration(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration) ConfigurationSet(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet) ByteArrayOutputStream(java.io.ByteArrayOutputStream) CAS(org.apache.uima.cas.CAS) IAnnotationUnit(org.dkpro.statistics.agreement.IAnnotationUnit) FSUtil(org.apache.uima.fit.util.FSUtil) ArrayList(java.util.ArrayList) ByteArrayInputStream(java.io.ByteArrayInputStream) CSVFormat(org.apache.commons.csv.CSVFormat) Arrays.asList(java.util.Arrays.asList) ObjectUtils(org.apache.commons.lang3.ObjectUtils) Map(java.util.Map) OutputStreamWriter(java.io.OutputStreamWriter) FeatureStructure(org.apache.uima.cas.FeatureStructure) Position(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.api.Position) PrintStream(java.io.PrintStream) TypeSystem(org.apache.uima.cas.TypeSystem) CodingAnnotationStudy(org.dkpro.statistics.agreement.coding.CodingAnnotationStudy) CodingAgreementResult(de.tudarmstadt.ukp.clarin.webanno.agreement.results.coding.CodingAgreementResult) ArrayFS(org.apache.uima.cas.ArrayFS) Collection(java.util.Collection) ICodingAnnotationItem(org.dkpro.statistics.agreement.coding.ICodingAnnotationItem) IOException(java.io.IOException) RelationDiffAdapter(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationDiffAdapter) CasUtil(org.apache.uima.fit.util.CasUtil) List(java.util.List) RelationPosition(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationPosition) ICodingAnnotationStudy(org.dkpro.statistics.agreement.coding.ICodingAnnotationStudy) Collections(java.util.Collections) CSVPrinter(org.apache.commons.csv.CSVPrinter) InputStream(java.io.InputStream) ExceptionUtils(org.apache.commons.lang3.exception.ExceptionUtils) TypeSystem(org.apache.uima.cas.TypeSystem) Configuration(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration) Position(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.api.Position) RelationPosition(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationPosition) ArrayList(java.util.ArrayList) CodingAnnotationStudy(org.dkpro.statistics.agreement.coding.CodingAnnotationStudy) ICodingAnnotationStudy(org.dkpro.statistics.agreement.coding.ICodingAnnotationStudy) CodingAgreementResult(de.tudarmstadt.ukp.clarin.webanno.agreement.results.coding.CodingAgreementResult) FeatureStructure(org.apache.uima.cas.FeatureStructure) ConfigurationSet(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) CAS(org.apache.uima.cas.CAS) RelationDiffAdapter(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationDiffAdapter) ArrayList(java.util.ArrayList) Arrays.asList(java.util.Arrays.asList) List(java.util.List) RelationPosition(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationPosition)

Example 4 with Configuration

use of de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration in project webanno by webanno.

the class SuggestionBuilder method buildCurationContainer.

public CurationContainer buildCurationContainer(AnnotatorState aState) throws UIMAException, ClassNotFoundException, IOException, AnnotationException {
    CurationContainer curationContainer = new CurationContainer();
    // initialize Variables
    SourceDocument sourceDocument = aState.getDocument();
    Map<Integer, Integer> segmentBeginEnd = new HashMap<>();
    Map<Integer, Integer> segmentNumber = new HashMap<>();
    Map<String, Map<Integer, Integer>> segmentAdress = new HashMap<>();
    // get annotation documents
    List<AnnotationDocument> finishedAnnotationDocuments = new ArrayList<>();
    for (AnnotationDocument annotationDocument : documentService.listAnnotationDocuments(aState.getDocument())) {
        if (annotationDocument.getState().equals(AnnotationDocumentState.FINISHED)) {
            finishedAnnotationDocuments.add(annotationDocument);
        }
    }
    Map<String, CAS> casses = new HashMap<>();
    AnnotationDocument randomAnnotationDocument = null;
    CAS mergeCas;
    // get the correction/automation CAS for the logged in user
    if (aState.getMode().equals(AUTOMATION) || aState.getMode().equals(CORRECTION)) {
        casses = listCasesforCorrection(randomAnnotationDocument, sourceDocument, aState.getMode());
        mergeCas = getMergeCas(aState, sourceDocument, casses, randomAnnotationDocument, false, false, false);
        String username = casses.keySet().iterator().next();
        updateSegment(aState, segmentBeginEnd, segmentNumber, segmentAdress, casses.get(username), username, aState.getWindowBeginOffset(), aState.getWindowEndOffset());
    } else {
        casses = listCassesforCuration(finishedAnnotationDocuments, aState.getMode());
        mergeCas = getMergeCas(aState, sourceDocument, casses, randomAnnotationDocument, false, false, false);
        updateSegment(aState, segmentBeginEnd, segmentNumber, segmentAdress, mergeCas, CURATION_USER, getFirstSentence(mergeCas).getBegin(), mergeCas.getDocumentText().length());
    }
    segmentAdress.put(CURATION_USER, new HashMap<>());
    Type sentenceType = getType(mergeCas, Sentence.class);
    for (AnnotationFS s : selectCovered(mergeCas, sentenceType, diffRangeBegin, diffRangeEnd)) {
        segmentAdress.get(CURATION_USER).put(s.getBegin(), getAddr(s));
    }
    List<DiffAdapter> adapters = getDiffAdapters(schemaService, aState.getAnnotationLayers());
    long diffStart = System.currentTimeMillis();
    log.debug("Calculating differences...");
    int count = 0;
    for (Integer begin : segmentBeginEnd.keySet()) {
        Integer end = segmentBeginEnd.get(begin);
        count++;
        if (count % 100 == 0) {
            log.debug("Processing differences: {} of {} sentences...", count, segmentBeginEnd.size());
        }
        DiffResult diff = doDiffSingle(adapters, LINK_ROLE_AS_LABEL, casses, begin, end).toResult();
        SourceListView curationSegment = new SourceListView();
        curationSegment.setBegin(begin);
        curationSegment.setEnd(end);
        curationSegment.setSentenceNumber(segmentNumber.get(begin));
        if (diff.hasDifferences() || !diff.getIncompleteConfigurationSets().isEmpty()) {
            // Is this confSet a diff due to stacked annotations (with same configuration)?
            boolean stackedDiff = false;
            stackedDiffSet: for (ConfigurationSet d : diff.getDifferingConfigurationSets().values()) {
                for (Configuration c : d.getConfigurations()) {
                    if (c.getCasGroupIds().size() != d.getCasGroupIds().size()) {
                        stackedDiff = true;
                        break stackedDiffSet;
                    }
                }
            }
            if (stackedDiff) {
                curationSegment.setSentenceState(DISAGREE);
            } else if (!diff.getIncompleteConfigurationSets().isEmpty()) {
                curationSegment.setSentenceState(DISAGREE);
            } else {
                curationSegment.setSentenceState(AGREE);
            }
        } else {
            curationSegment.setSentenceState(AGREE);
        }
        for (String username : segmentAdress.keySet()) {
            curationSegment.getSentenceAddress().put(username, segmentAdress.get(username).get(begin));
        }
        curationContainer.getCurationViewByBegin().put(begin, curationSegment);
    }
    log.debug("Difference calculation completed in {}ms", (System.currentTimeMillis() - diffStart));
    return curationContainer;
}
Also used : Configuration(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AnnotationDocument(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocument) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) DiffResult(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.DiffResult) SourceDocument(de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument) DiffAdapter(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.api.DiffAdapter) ConfigurationSet(de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet) Type(org.apache.uima.cas.Type) CasUtil.getType(org.apache.uima.fit.util.CasUtil.getType) CAS(org.apache.uima.cas.CAS) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

Configuration (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.Configuration)4 ConfigurationSet (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.ConfigurationSet)4 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 CAS (org.apache.uima.cas.CAS)2 FeatureStructure (org.apache.uima.cas.FeatureStructure)2 AnnotationFS (org.apache.uima.cas.text.AnnotationFS)2 CodingAgreementResult (de.tudarmstadt.ukp.clarin.webanno.agreement.results.coding.CodingAgreementResult)1 TypeAdapter (de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.TypeAdapter)1 VID (de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.VID)1 WebAnnoCasUtil.getFeature (de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.getFeature)1 CasDiff (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff)1 DiffResult (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.CasDiff.DiffResult)1 LinkCompareBehavior (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.LinkCompareBehavior)1 DiffAdapter (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.api.DiffAdapter)1 Position (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.api.Position)1 RelationDiffAdapter (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationDiffAdapter)1 RelationPosition (de.tudarmstadt.ukp.clarin.webanno.curation.casdiff.relation.RelationPosition)1 AnnotationDocument (de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocument)1 AnnotationFeature (de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature)1