001/** 002 * Copyright (C) 2007 - 2016, Jens Lehmann 003 * 004 * This file is part of DL-Learner. 005 * 006 * DL-Learner is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation; either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * DL-Learner is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.dllearner.utilities; 020 021import com.clarkparsia.owlapiv3.XSD; 022import com.google.common.collect.Iterables; 023import com.google.common.collect.Sets; 024import org.apache.commons.lang3.Range; 025import org.dllearner.core.AbstractReasonerComponent; 026import org.dllearner.utilities.owl.SimpleOWLEntityChecker; 027import org.jetbrains.annotations.NotNull; 028import org.joda.time.DateTime; 029import org.joda.time.format.*; 030import org.semanticweb.owlapi.apibinding.OWLManager; 031import org.semanticweb.owlapi.manchestersyntax.parser.ManchesterOWLSyntaxClassExpressionParser; 032import org.semanticweb.owlapi.manchestersyntax.parser.ManchesterOWLSyntaxParserException; 033import org.semanticweb.owlapi.model.*; 034import org.semanticweb.owlapi.vocab.XSDVocabulary; 035import org.slf4j.Logger; 036import uk.ac.manchester.cs.owl.owlapi.OWLDatatypeImpl; 037 038import java.util.*; 039import java.util.function.Supplier; 040 041/** 042 * A collection of utility methods for the OWL API. 043 * 044 * @author Lorenz Buehmann 045 * 046 */ 047public class OWLAPIUtils { 048 049 private static final OWLCLassExpressionToOWLClassTransformer OWL_CLASS_TRANSFORM_FUNCTION = new OWLCLassExpressionToOWLClassTransformer(); 050 051 public static final OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); 052 public static final OWLDataFactory factory = manager.getOWLDataFactory(); 053 054 public final static Set<OWLDatatype> intDatatypes = new TreeSet<>(Arrays.asList( 055 XSD.INT, 056 XSD.INTEGER, 057 XSD.POSITIVE_INTEGER, 058 XSD.NEGATIVE_INTEGER, 059 XSD.NON_POSITIVE_INTEGER, 060 XSD.NON_NEGATIVE_INTEGER, 061 XSD.SHORT, 062 XSD.BYTE, 063 XSD.UNSIGNED_INT, 064 XSD.UNSIGNED_LONG 065 )); 066 public final static Set<OWLDatatype> floatDatatypes = new TreeSet<>(Arrays.asList( 067 XSD.FLOAT, 068 XSD.DOUBLE, 069 factory.getOWLDatatype(XSDVocabulary.DECIMAL.getIRI()) 070 071 )); 072 public final static Set<OWLDatatype> fixedDatatypes = new TreeSet<>(Collections.singletonList( 073 XSD.BOOLEAN 074 )); 075 076 /** 077 * The OWL 2 datatypes for the representation of time instants with and 078 * without time zone offsets. 079 */ 080 public final static Set<OWLDatatype> owl2TimeDatatypes = Sets.newTreeSet(Arrays.asList( 081 factory.getOWLDatatype(XSDVocabulary.DATE_TIME.getIRI()), 082 factory.getOWLDatatype(XSDVocabulary.DATE_TIME_STAMP.getIRI()) 083 )); 084 085 public final static Set<OWLDatatype> dtDatatypes = Sets.newTreeSet(Arrays.asList( 086 XSD.DATE, 087 XSD.DATE_TIME, 088 XSD.G_DAY, 089 XSD.G_MONTH, 090 XSD.G_YEAR 091 )); 092 093 public final static Set<OWLDatatype> periodDatatypes = Sets.newTreeSet(Arrays.asList( 094 XSD.DURATION, 095 new OWLDatatypeImpl(IRI.create(org.apache.jena.vocabulary.XSD.getURI() + "yearMonthDuration")), 096 new OWLDatatypeImpl(IRI.create(org.apache.jena.vocabulary.XSD.getURI() + "dayTimeDuration")) 097 )); 098 099 public static final Set<OWLDatatype> numericDatatypes = Sets.union(intDatatypes, floatDatatypes); 100 101 private static final Map<OWLDatatype, Class<?>> javaTypeMap; 102 static { 103 javaTypeMap = new TreeMap<>(); 104 javaTypeMap.put(XSD.BYTE, Byte.class); 105 javaTypeMap.put(XSD.SHORT, Short.class); 106 javaTypeMap.put(factory.getOWLDatatype(XSDVocabulary.DECIMAL.getIRI()), Double.class); 107 javaTypeMap.put(XSD.INT, Integer.class); 108 javaTypeMap.put(XSD.INTEGER, Integer.class); 109 javaTypeMap.put(XSD.POSITIVE_INTEGER, Integer.class); 110 javaTypeMap.put(XSD.NEGATIVE_INTEGER, Integer.class); 111 javaTypeMap.put(XSD.NON_NEGATIVE_INTEGER, Integer.class); 112 javaTypeMap.put(XSD.NON_POSITIVE_INTEGER, Integer.class); 113 javaTypeMap.put(XSD.LONG, Long.class); 114 javaTypeMap.put(XSD.DOUBLE, Double.class); 115 javaTypeMap.put(XSD.FLOAT, Float.class); 116 javaTypeMap.put(XSD.BOOLEAN , Boolean.class); 117 //javaTypeMap.put(OWL2Datatype.XSD_STRING, String.class); 118 //javaTypeMap.put(OWL2Datatype.XSD_, .class); 119 } 120 121 public static final Map<OWLDatatype, DateTimeFormatter> dateTimeFormatters = new HashMap<>(); 122 static { 123 dateTimeFormatters.put(XSD.G_YEAR, ISODateTimeFormat.year()); 124 dateTimeFormatters.put(XSD.G_YEAR_MONTH, ISODateTimeFormat.yearMonth()); 125 dateTimeFormatters.put(XSD.G_MONTH, DateTimeFormat.forPattern("--MM").withZoneUTC()); 126 dateTimeFormatters.put(XSD.G_MONTH_DAY, DateTimeFormat.forPattern("--MM-DD").withZoneUTC()); 127 dateTimeFormatters.put(XSD.G_DAY, DateTimeFormat.forPattern("---DD").withZoneUTC()); 128 dateTimeFormatters.put(XSD.TIME, DateTimeFormat.forPattern("hh:mm:ss.sss").withOffsetParsed()); 129 dateTimeFormatters.put(XSD.DATE, ISODateTimeFormat.date()); 130 dateTimeFormatters.put(XSD.DATE_TIME, ISODateTimeFormat.dateHourMinuteSecond()); // .dateTimeNoMillis()); 131 dateTimeFormatters.put(factory.getOWLDatatype(XSDVocabulary.DATE_TIME_STAMP.getIRI()), ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed()); 132 } 133 134 public static final Map<OWLDatatype, DateTimeFormatter> dateTimeParsers = new HashMap<>(dateTimeFormatters); 135 static { 136// dateTimeParsers.put(XSD.G_YEAR, ISODateTimeFormat.year()); 137// dateTimeParsers.put(XSD.G_YEAR_MONTH, ISODateTimeFormat.yearMonth()); 138 dateTimeParsers.put(XSD.G_MONTH, new DateTimeFormatterBuilder() 139 .append(DateTimeFormat.forPattern("--MM")) 140 .appendOptional(DateTimeFormat.forPattern("Z").getParser()) 141 .toFormatter().withZoneUTC()); 142 dateTimeParsers.put(XSD.G_MONTH_DAY, new DateTimeFormatterBuilder() 143 .append(DateTimeFormat.forPattern("--MM-DD")) 144 .appendOptional(DateTimeFormat.forPattern("Z").getParser()) 145 .toFormatter().withZoneUTC()); 146 dateTimeParsers.put(XSD.G_DAY, new DateTimeFormatterBuilder() 147 .append(DateTimeFormat.forPattern("---DD")) 148 .appendOptional(DateTimeFormat.forPattern("Z").getParser()) 149 .toFormatter().withZoneUTC()); 150// dateTimeParsers.put(XSD.TIME, DateTimeFormat.forPattern("hh:mm:ss.sss").withOffsetParsed()); 151// dateTimeParsers.put(XSD.DATE, ISODateTimeFormat.date()); 152 dateTimeParsers.put(XSD.DATE_TIME, new DateTimeFormatterBuilder() 153 .append(DateTimeFormat.forPattern("yyyy-MM-DD'T'HH:mm:ss")) 154 .appendOptional(new DateTimeFormatterBuilder() 155 .appendLiteral('.') 156 .appendFractionOfSecond(1,4) 157 .toParser()) 158 .appendOptional(DateTimeFormat.forPattern("Z").getParser()) 159 .toFormatter().withZoneUTC()); 160// dateTimeParsers.put(XSD.DATE_TIME, ISODateTimeFormat.dateHourMinuteSecond()); // .dateTimeNoMillis()); 161// dateTimeParsers.put(OWL2DatatypeImpl.getDatatype(OWL2Datatype.XSD_DATE_TIME_STAMP), ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed()); 162 } 163 164 public static final Map<OWLDatatype, PeriodFormatter> periodFormatters = new HashMap<>(); 165 static { 166 periodFormatters.put(XSD.DURATION, ISOPeriodFormat.standard()); 167 periodFormatters.put(new OWLDatatypeImpl(IRI.create(org.apache.jena.vocabulary.XSD.getURI() + "dayTimeDuration")), 168 new PeriodFormatterBuilder()//PnDTnHnMnS 169 .appendLiteral("P") 170 .appendDays() 171 .appendSuffix("D") 172 .appendSeparatorIfFieldsAfter("T") 173 .appendHours() 174 .appendSuffix("H") 175 .appendMinutes() 176 .appendSuffix("M") 177 .appendSecondsWithOptionalMillis() 178 .appendSuffix("S") 179 .toFormatter()); 180 periodFormatters.put(new OWLDatatypeImpl(IRI.create(org.apache.jena.vocabulary.XSD.getURI() + "yearMonthDuration")), 181 new PeriodFormatterBuilder()//PnYnM 182 .appendLiteral("P") 183 .appendYears() 184 .appendSuffix("Y") 185 .appendMonths() 186 .appendSuffix("M") 187 .toFormatter()); 188 189 } 190 191 /** 192 * @param entityType the OWL entity type 193 * @return the name of the OWL entity type 194 */ 195 public static String getPrintName(EntityType entityType) { 196 return entityType.getPrintName().toLowerCase(); 197 } 198 199 /** 200 * @param lit the OWL literal 201 * @return whether the OWL literal is an integer, i.e. whether the datatype is some integer 202 */ 203 public static boolean isIntegerDatatype(OWLLiteral lit) { 204 return intDatatypes.contains(lit.getDatatype()); 205 } 206 207 public static boolean isIntegerDatatype(OWLDatatype datatype) { 208 return intDatatypes.contains(datatype); 209 } 210 211 public static boolean isNumericDatatype(OWLDatatype datatype){ 212 return numericDatatypes.contains(datatype); 213 } 214 215 /** 216 * Convenience method that converts a set of OWL class expressions to a set of OWL classes. 217 * @param classExpressions a set of OWL class expressions 218 * @return a set of OWL classes 219 */ 220 public static Set<OWLClass> asOWLClasses(Set<OWLClassExpression> classExpressions) { 221 return Sets.newHashSet(Iterables.transform(classExpressions, OWL_CLASS_TRANSFORM_FUNCTION)); 222 } 223 224 public static final String UNPARSED_OCE = "dllearner+unparsed:"; 225 226 227 public static OWLClassExpression classExpressionPropertyExpander (OWLClassExpression startClass, AbstractReasonerComponent reasoner, OWLDataFactory dataFactory, boolean sfp) { 228 if(!startClass.isAnonymous() && startClass.asOWLClass().getIRI().toString().startsWith(UNPARSED_OCE)) { 229 try { 230 String s = startClass.asOWLClass().getIRI().toString().substring(UNPARSED_OCE.length()); 231 return fromManchester(s, reasoner, dataFactory, sfp); 232 } catch (ManchesterOWLSyntaxParserException e) { 233 throw new RuntimeException("Parsing of class expression in OWL Manchester Syntax failed. Please check the syntax and " 234 + "remember to use either full IRIs or prefixed IRIs.", e); 235 } 236 } else { 237 return startClass; 238 } 239 240 } 241 public static OWLClassExpression classExpressionPropertyExpander (OWLClassExpression startClass, AbstractReasonerComponent reasoner, OWLDataFactory dataFactory) { 242 return classExpressionPropertyExpander(startClass, reasoner, dataFactory, false); 243 } 244 245 @NotNull 246 public static OWLClassExpression fromManchester(String expr, AbstractReasonerComponent reasoner, OWLDataFactory dataFactory) { 247 ManchesterOWLSyntaxClassExpressionParser parser = new ManchesterOWLSyntaxClassExpressionParser(dataFactory, new SimpleOWLEntityChecker(reasoner)); 248 return parser.parse(expr); 249 } 250 251 @NotNull 252 public static OWLClassExpression fromManchester(String expr, AbstractReasonerComponent reasoner, OWLDataFactory dataFactory, boolean shortForm) { 253 SimpleOWLEntityChecker oec = new SimpleOWLEntityChecker(reasoner); 254 oec.setAllowShortForm(shortForm); 255 ManchesterOWLSyntaxClassExpressionParser parser = new ManchesterOWLSyntaxClassExpressionParser(dataFactory, oec); 256 return parser.parse(expr); 257 } 258 259 /** 260 * Checks whether the given value is in the closed interval [min,max], i.e. 261 * the value is greater than min and lower than max. 262 * @param value the value 263 * @param min the lower interval endpoint 264 * @param max the upper interval endpoint 265 * @return whether the given value is in the closed interval [min,max] 266 */ 267 public static boolean inRange(OWLLiteral value, OWLLiteral min, OWLLiteral max) { 268 OWLDatatype datatype = value.getDatatype(); 269 270 if(OWLAPIUtils.dtDatatypes.contains(datatype)) { 271 DateTimeFormatter parser = OWLAPIUtils.dateTimeParsers.get(datatype); 272 273 // parse min 274 DateTime minDateTime = null; 275 if(min != null) { 276 minDateTime = parser.parseDateTime(min.getLiteral()); 277 } 278 279 // parse max 280 DateTime maxDateTime = null; 281 if(max != null) { 282 maxDateTime = parser.parseDateTime(max.getLiteral()); 283 } 284 285 // parse value 286 DateTime dateTime = parser.parseDateTime(value.getLiteral()); 287 288 if( 289 (minDateTime == null || (dateTime.isEqual(minDateTime) || dateTime.isAfter(minDateTime))) 290 && 291 (maxDateTime == null || (dateTime.isEqual(maxDateTime) || dateTime.isBefore(maxDateTime))) 292 ) 293 { 294 return true; 295 } 296 } else if(OWLAPIUtils.floatDatatypes.contains(datatype)) { 297 return Range.between(min.parseFloat(), max.parseFloat()).contains(value.parseFloat()); 298 } else if(OWLAPIUtils.intDatatypes.contains(datatype)) { 299 return Range.between(min.parseInteger(), max.parseInteger()).contains(value.parseInteger()); 300 } 301 302 return false; 303 } 304 305 public static OWLClassExpression classExpressionPropertyExpanderChecked(OWLClassExpression startClass, AbstractReasonerComponent reasoner, final OWLDataFactory df, Logger logger) { 306 return classExpressionPropertyExpanderChecked(startClass, reasoner, df, df::getOWLThing, logger); 307 } 308 309 public static OWLClassExpression classExpressionPropertyExpanderChecked(OWLClassExpression startClass, AbstractReasonerComponent reasoner, OWLDataFactory df, Supplier<OWLClassExpression> defaultClass, Logger logger, boolean sfp) { 310 if(startClass == null) { 311 if (defaultClass != null) 312 startClass = defaultClass.get(); 313 } else { 314 try { 315 startClass = OWLAPIUtils.classExpressionPropertyExpander(startClass, reasoner, df, sfp); 316 } catch (ManchesterOWLSyntaxParserException e) { 317 logger.info("Error parsing startClass: " + e.getMessage()); 318 startClass = defaultClass.get(); 319 logger.warn("Using "+ startClass +" instead."); 320 } 321 } 322 return startClass; 323 } 324 public static OWLClassExpression classExpressionPropertyExpanderChecked(OWLClassExpression startClass, AbstractReasonerComponent reasoner, OWLDataFactory df, Supplier<OWLClassExpression> defaultClass, Logger logger) { 325 return classExpressionPropertyExpanderChecked(startClass, reasoner, df, defaultClass, logger, false); 326 } 327 public static OWLClassExpression classExpressionPropertyExpanderChecked(OWLClassExpression startClass, AbstractReasonerComponent reasoner, OWLDataFactory df, boolean sfp, Logger logger) { 328 return classExpressionPropertyExpanderChecked(startClass, reasoner, df, null, logger, sfp); 329 } 330}