001package conexp.fx.core.dl; 002 003import java.util.Collections; 004import java.util.HashMap; 005 006/* 007 * #%L 008 * Concept Explorer FX 009 * %% 010 * Copyright (C) 2010 - 2019 Francesco Kriegel 011 * %% 012 * This program is free software: you can redistribute it and/or modify 013 * it under the terms of the GNU General Public License as 014 * published by the Free Software Foundation, either version 3 of the 015 * License, or (at your option) any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public 023 * License along with this program. If not, see 024 * <http://www.gnu.org/licenses/gpl-3.0.html>. 025 * #L% 026 */ 027 028import java.util.HashSet; 029import java.util.Map.Entry; 030import java.util.Set; 031import java.util.stream.Collectors; 032 033import org.semanticweb.owlapi.apibinding.OWLManager; 034import org.semanticweb.owlapi.model.AddAxiom; 035import org.semanticweb.owlapi.model.IRI; 036import org.semanticweb.owlapi.model.OWLDataFactory; 037import org.semanticweb.owlapi.model.OWLOntology; 038import org.semanticweb.owlapi.model.OWLOntologyCreationException; 039import org.semanticweb.owlapi.model.OWLOntologyManager; 040 041import conexp.fx.core.collections.relation.MatrixRelation; 042 043public class ELTBox { 044 045 private static final IRI NOTHING = OWLManager.getOWLDataFactory().getOWLNothing().getIRI(); 046 047 private final Set<ELConceptInclusion> conceptInclusions; 048 049 public ELTBox() { 050 super(); 051 this.conceptInclusions = new HashSet<>(); 052 } 053 054 public final Signature getSignature() { 055 final Signature sigma = new Signature(IRI.generateDocumentIRI()); 056 for (ELConceptInclusion ci : conceptInclusions) { 057 sigma.getConceptNames().addAll(ci.getSubsumee().getConceptNamesInSignature().collect(Collectors.toSet())); 058 sigma.getConceptNames().addAll(ci.getSubsumer().getConceptNamesInSignature().collect(Collectors.toSet())); 059 sigma.getRoleNames().addAll(ci.getSubsumee().getRoleNamesInSignature().collect(Collectors.toSet())); 060 sigma.getRoleNames().addAll(ci.getSubsumer().getRoleNamesInSignature().collect(Collectors.toSet())); 061 } 062 return sigma; 063 } 064 065 public final Set<ELConceptInclusion> getConceptInclusions() { 066 return conceptInclusions; 067 } 068 069 private final class CanonicalModelBuilder { 070 071 private final ELConceptDescription C; 072 private final ELInterpretation2<ELConceptDescription> canmod; 073 074 private CanonicalModelBuilder(final ELConceptDescription C) { 075 super(); 076 this.C = C; 077 this.canmod = new ELInterpretation2<>(); 078 } 079 080 private final void insert(final ELConceptDescription D) { 081 insert(D, D); 082 } 083 084 private final void insert(final ELConceptDescription X, final ELConceptDescription D) { 085 for (IRI A : D.getConceptNames()) 086 canmod.getConceptNameExtensionMatrix().add(X, A); 087 for (Entry<IRI, ELConceptDescription> rE : D.getExistentialRestrictions().entries()) { 088 canmod.getRoleNameExtensionMatrix(rE.getKey()).add(X, rE.getValue()); 089 insert(rE.getValue()); 090 } 091 } 092 093 private final ELInterpretation2<ELConceptDescription> buildAndGet() { 094 insert(C); 095 boolean changed = true; 096 while (changed) { 097 changed = false; 098 for (ELConceptInclusion ci : conceptInclusions) 099 for (ELConceptDescription o : new HashSet<>(canmod.getDomain())) { 100 final ELConceptDescription char1 = 101 canmod.getMostSpecificConceptDescription(Collections.singleton(o), ci.getSubsumee().roleDepth()); 102 final ELConceptDescription char2 = 103 canmod.getMostSpecificConceptDescription(Collections.singleton(o), ci.getSubsumer().roleDepth()); 104 if (char1.isSubsumedBy(ci.getSubsumee()) && !char2.isSubsumedBy(ci.getSubsumer())) { 105 insert(o, ci.getSubsumer()); 106 changed = true; 107 } 108 } 109 } 110 changed = true; 111 while (changed) { 112 changed = false; 113 for (ELConceptDescription o : canmod.getDomain()) 114 if (canmod.getConceptNameExtensionMatrix().contains(o, NOTHING)) 115 for (MatrixRelation<ELConceptDescription, ELConceptDescription> r : canmod 116 .getRoleNameExtensionMatrixMap() 117 .values()) 118 if (r.colHeads().contains(o)) 119 for (ELConceptDescription p : r.col(o)) 120 changed |= canmod.add(p, NOTHING); 121 } 122 for (ELConceptDescription o : canmod.getDomain()) 123 if (canmod.getConceptNameExtensionMatrix().contains(o, NOTHING)) { 124 canmod.getConceptNameExtensionMatrix().row(o).retainAll(Collections.singleton(NOTHING)); 125 for (MatrixRelation<ELConceptDescription, ELConceptDescription> r : canmod 126 .getRoleNameExtensionMatrixMap() 127 .values()) 128 if (r.rowHeads().contains(o)) 129 r.row(o).clear(); 130 } 131 return this.canmod; 132 } 133 134 } 135 136 public final ELInterpretation2<ELConceptDescription> getCanonicalModel(final ELConceptDescription C) { 137 return new CanonicalModelBuilder(C).buildAndGet(); 138 } 139 140 public final ELConceptDescription getMostSpecificConsequence(final ELConceptDescription C, final int roleDepth) { 141 return getCanonicalModel(C).getMostSpecificConceptDescription(Collections.singleton(C), roleDepth); 142 } 143 144 private final class CanonicalModelBuilderLutz { 145 146 private final ELConceptDescription C; 147 private final ELInterpretation2<ELConceptDescription> canmod; 148 private final Set<Entry<IRI, ELConceptDescription>> exsubT; 149 private final Set<ELConceptDescription> domain; 150 private final Set<IRI> conceptNames = new HashSet<>(); 151 private final Set<IRI> roleNames = new HashSet<>(); 152 153 private CanonicalModelBuilderLutz(final ELConceptDescription C) { 154 super(); 155 this.C = C; 156 this.canmod = new ELInterpretation2<>(); 157 this.exsubT = new HashSet<>(); 158 this.domain = new HashSet<>(); 159 } 160 161 private final void populate_exsubT(final ELConceptDescription X) { 162 exsubT.addAll(X.getExistentialRestrictions().entries()); 163 for (ELConceptDescription Y : X.getExistentialRestrictions().values()) 164 populate_exsubT(Y); 165 } 166 167 private final void populate_domain(final ELConceptDescription X) { 168 domain.addAll(X.getExistentialRestrictions().values()); 169 for (ELConceptDescription Y : X.getExistentialRestrictions().values()) 170 populate_domain(Y); 171 } 172 173 private final void populate_signature(final ELConceptDescription X) { 174 conceptNames.addAll(X.getConceptNames()); 175 roleNames.addAll(X.getExistentialRestrictions().keys()); 176 for (ELConceptDescription Y : X.getExistentialRestrictions().values()) 177 populate_signature(Y); 178 } 179 180 private final ELInterpretation2<ELConceptDescription> buildAndGet() { 181 for (ELConceptInclusion ci : conceptInclusions) { 182 populate_exsubT(ci.getSubsumee()); 183 populate_exsubT(ci.getSubsumer()); 184 } 185 domain.add(C); 186 populate_domain(C); 187 for (Entry<IRI, ELConceptDescription> e : exsubT) 188 domain.add(e.getValue()); 189 populate_signature(C); 190 for (ELConceptInclusion ci : conceptInclusions) { 191 populate_signature(ci.getSubsumee()); 192 populate_signature(ci.getSubsumer()); 193 } 194 for (ELConceptDescription D : domain) { 195 for (IRI A : conceptNames) 196 if (ELReasoner.isSubsumedBy(D, ELConceptDescription.conceptName(A), ELTBox.this)) 197 canmod.getConceptNameExtensionMatrix().add(D, A); 198 for (ELConceptDescription E : domain) 199 for (IRI r : roleNames) { 200 final HashMap<IRI, ELConceptDescription> hashMap = new HashMap<>(); 201 hashMap.put(r, E); 202 final Entry<IRI, ELConceptDescription> rE = hashMap.entrySet().iterator().next(); 203 if ((exsubT.contains(rE) 204 && ELReasoner.isSubsumedBy(D, ELConceptDescription.existentialRestriction(rE), ELTBox.this)) 205 || D.getExistentialRestrictions().containsEntry(r, E)) 206 canmod.getRoleNameExtensionMatrix(r).add(D, E); 207 } 208 } 209 return canmod; 210 } 211 212 } 213 214 public final ELInterpretation2<ELConceptDescription> getCanonicalModelLutz(final ELConceptDescription C) { 215 return new CanonicalModelBuilderLutz(C).buildAndGet(); 216 } 217 218 public final ELConceptDescription getMostSpecificConsequenceLutz(final ELConceptDescription C, final int roleDepth) { 219 return getCanonicalModelLutz(C).getMostSpecificConceptDescription(Collections.singleton(C), roleDepth); 220 } 221 222 @Override 223 public boolean equals(Object obj) { 224 if (obj == null) 225 return false; 226 if (!(obj instanceof ELTBox)) 227 return false; 228 final ELTBox other = (ELTBox) obj; 229 return this.conceptInclusions.equals(other.conceptInclusions); 230 } 231 232 public final OWLOntology toOWLOntology() { 233 try { 234 final OWLOntologyManager om = OWLManager.createOWLOntologyManager(); 235 final OWLDataFactory df = om.getOWLDataFactory(); 236 final OWLOntology ontology = om.createOntology(); 237 conceptInclusions 238 .parallelStream() 239 .forEach( 240 gci -> om 241 .applyChange( 242 new AddAxiom( 243 ontology, 244 df 245 .getOWLSubClassOfAxiom( 246 gci.getSubsumee().clone().reduce().toOWLClassExpression(), 247 gci.getSubsumer().clone().reduce().toOWLClassExpression())))); 248 return ontology; 249 } catch (OWLOntologyCreationException e) { 250 throw new RuntimeException(e); 251 } 252 } 253 254 @Override 255 public int hashCode() { 256 return 23 * conceptInclusions.hashCode() + 99; 257 } 258 259 @Override 260 public String toString() { 261 return "EL-TBox " + conceptInclusions.toString(); 262 } 263 264}