Java tutorial
/* * Copyright 2014 Hugo m09? Mougard. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package eu.crydee.alignment.aligner.ae; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Lists; import com.google.common.collect.Table; import eu.crydee.alignment.aligner.ts.Document; import eu.crydee.alignment.metricslab.model.Alignment; import eu.crydee.alignment.metricslab.model.Complete; import eu.crydee.alignment.metricslab.model.annotations.Metric; import eu.crydee.alignment.metricslab.model.exceptions.TAFParseException; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; import org.apache.commons.math3.stat.inference.TestUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.uima.UimaContext; import org.apache.uima.analysis_engine.AnalysisEngineProcessException; import org.apache.uima.fit.component.JCasAnnotator_ImplBase; import org.apache.uima.fit.descriptor.ConfigurationParameter; import org.apache.uima.fit.util.JCasUtil; import org.apache.uima.jcas.JCas; import org.apache.uima.resource.ResourceInitializationException; /** * * @author Hugo m09? Mougard */ public class MetricsOneVsOneC extends JCasAnnotator_ImplBase { private static final Logger logger = LogManager.getLogger(MetricsOneVsOneC.class); public static final String PARAM_TAF_FOLDER_1 = "TAF_FOLDER_1"; @ConfigurationParameter(name = PARAM_TAF_FOLDER_1, mandatory = true) private String tafFolder1; public static final String PARAM_TAF_FOLDER_2 = "TAF_FOLDER_2"; @ConfigurationParameter(name = PARAM_TAF_FOLDER_2, mandatory = true) private String tafFolder2; public static final String PARAM_LEFT_ALGO_NAME = "LEFT_ALGO_NAME"; @ConfigurationParameter(name = PARAM_LEFT_ALGO_NAME, mandatory = true) private String leftAlgoName; public static final String PARAM_RIGHT_ALGO_NAME = "RIGHT_ALGO_NAME"; @ConfigurationParameter(name = PARAM_RIGHT_ALGO_NAME, mandatory = true) private String rightAlgoName; public static final String PARAM_HTML_OUTPUT_FILEPATH = "HTML_OUTPUT_FILEPATH"; @ConfigurationParameter(name = PARAM_HTML_OUTPUT_FILEPATH, mandatory = true) private String htmlFilepath; public static final String PARAM_METRICS_TO_SUMMARIZE = "METRICS_TO_SUMMARIZE"; @ConfigurationParameter(name = PARAM_METRICS_TO_SUMMARIZE, mandatory = true) String[] keysArray; private Table<String, String, Pair<Double, Double>> results; private Map<String, Pair<Method, String>> methodsMetadata; private List<String> keys; @Override public void initialize(UimaContext context) throws ResourceInitializationException { super.initialize(context); results = HashBasedTable.create(); keys = Lists.newArrayList(keysArray); methodsMetadata = Arrays.stream(Complete.class.getMethods()) .map(m -> Pair.of(m, m.getAnnotation(Metric.class))) .filter(p -> p.getRight() != null && keys.contains(p.getRight().key())) .collect(Collectors.toMap(p -> p.getRight().key(), p -> Pair.of(p.getLeft(), p.getRight().name()))); } @Override public void process(JCas jcas) throws AnalysisEngineProcessException { String name = JCasUtil.selectSingle(jcas, Document.class).getName(); try { Alignment alignment1 = Alignment.fromTAF( FileUtils.readFileToString(new File(tafFolder1, name + ".taf"), StandardCharsets.UTF_8)), alignment2 = Alignment.fromTAF(FileUtils.readFileToString(new File(tafFolder2, name + ".taf"), StandardCharsets.UTF_8)); for (String k : keys) { double r1 = (double) methodsMetadata.get(k).getLeft().invoke(alignment1.complete), r2 = (double) methodsMetadata.get(k).getLeft().invoke(alignment2.complete); results.put(name, k, Pair.of(r1, r2)); } } catch (TAFParseException ex) { logger.error("Couldn't parse the TAF when trying to compute graph " + "metrics."); throw new AnalysisEngineProcessException(ex); } catch (IOException ex) { logger.error("Couldn't read the TAF when trying to compute graph " + "metrics."); throw new AnalysisEngineProcessException(ex); } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException ex) { logger.error("Couldn't compute one of the metrics."); throw new AnalysisEngineProcessException(ex); } } @Override public void collectionProcessComplete() throws AnalysisEngineProcessException { try { String template = IOUtils.toString(getClass() .getResourceAsStream("/eu/crydee/alignment/aligner/ae/" + "metrics-one-vs-one-template.html")); template = template.replace("@@TITLE@@", "Metrics comparator" + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)); template = template.replace("@@LEFTALGO@@", leftAlgoName); template = template.replace("@@RIGHTALGO@@", rightAlgoName); StringBuilder sb = new StringBuilder(); sb.append("<table class=\"table table-condensed\">\n").append(" <thead>\n") .append(" <tr>\n").append(" <th>Document\\Metric</th>\n"); for (String key : keys) { sb.append(" <th colspan=\"2\">").append(methodsMetadata.get(key).getRight()) .append("</th>\n"); } sb.append(" <tr>\n").append(" </thead>\n").append(" <tbody>\n") .append(" <tr>\n").append(" <td>\n") .append(" <strong>Total</strong>\n") .append(" </td>\n"); for (String key : keys) { SummaryStatistics ss1 = new SummaryStatistics(), ss2 = new SummaryStatistics(); List<Pair<Double, Double>> column = results.column(key).values().stream().peek(p -> { ss1.addValue(p.getLeft()); ss2.addValue(p.getRight()); }).collect(Collectors.toList()); boolean significant = TestUtils.pairedTTest(column.stream().mapToDouble(p -> p.getLeft()).toArray(), column.stream().mapToDouble(p -> p.getRight()).toArray(), 0.05); double mean1 = ss1.getMean(), mean2 = ss2.getMean(); boolean above = mean1 > mean2; String summary1 = String.format("%.3f", mean1) + "<small class=\"text-muted\">" + "" + String.format("%.3f", ss1.getStandardDeviation()) + "</small>", summary2 = String.format("%.3f", mean2) + "<small class=\"text-muted\">" + "" + String.format("%.3f", ss2.getStandardDeviation()) + "</small>"; sb.append(" <td class=\"") .append(significant ? (above ? "success" : "danger") : "warning").append("\">") .append(summary1).append("</td>\n"); sb.append(" <td class=\"") .append(significant ? (!above ? "success" : "danger") : "warning").append("\">") .append(summary2).append("</td>\n"); } sb.append(" </tr>\n"); SortedSet<String> rows = new TreeSet<>(results.rowKeySet()); for (String row : rows) { sb.append(" <tr>\n").append(" <td>").append(row) .append("</td>\n"); for (String key : keys) { Pair<Double, Double> r = results.get(row, key); sb.append(" <td>").append(String.format("%.3f", r.getLeft())) .append("</td>\n").append(" <td>") .append(String.format("%.3f", r.getRight())).append("</td>\n"); } sb.append(" </tr>\n"); } sb.append(" </tbody>\n").append(" </table>"); FileUtils.write(new File(htmlFilepath), template.replace("@@TABLE@@", sb.toString()), StandardCharsets.UTF_8); } catch (IOException ex) { logger.error("IO problem with the HTML output."); throw new AnalysisEngineProcessException(ex); } } }