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}