001package conexp.fx.core.dl;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2019 Francesco Kriegel
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.util.Arrays;
026import java.util.Collection;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.Set;
030import java.util.stream.Collectors;
031
032import org.semanticweb.owlapi.apibinding.OWLManager;
033import org.semanticweb.owlapi.model.IRI;
034import org.semanticweb.owlapi.model.OWLClassExpression;
035import org.semanticweb.owlapi.model.OWLDataFactory;
036
037import com.google.common.collect.Sets;
038
039import conexp.fx.core.collections.Collections3;
040import conexp.fx.core.collections.Pair;
041
042public class ELLeastCommonSubsumer {
043
044  private static final OWLDataFactory df = OWLManager.getOWLDataFactory();
045
046//  private static final Map<Set<ELConceptDescription>, ELConceptDescription> lcsCache =
047//      new HashMap<Set<ELConceptDescription>, ELConceptDescription>();
048//
049//  protected static final ELConceptDescription
050//      _of(final ELConceptDescription concept1, final ELConceptDescription concept2) {
051//    final Set<ELConceptDescription> _concepts = Sets.newHashSet(concept1, concept2);
052//    final ELConceptDescription _lcs = lcsCache.get(_concepts);
053//    if (_lcs != null)
054//      return _lcs.clone();
055//    if (concept1.isBot())
056//      return concept2;
057//    if (concept2.isBot())
058//      return concept1;
059//    if (concept1.isTop())
060//      return concept1;
061//    if (concept2.isTop())
062//      return concept2;
063////    System.out.println("computing lcs of " + concept1 + " and " + concept2);
064//    final Set<IRI> commonNames = new HashSet<IRI>();
065//    commonNames.addAll(Sets.intersection(concept1.getConceptNames(), concept2.getConceptNames()));
066//    final Set<Pair<IRI, ELConceptDescription>> commonRestrictions = new HashSet<Pair<IRI, ELConceptDescription>>();
067//    for (Pair<IRI, ELConceptDescription> existentialRestriction1 : concept1.getExistentialRestrictions())
068//      for (Pair<IRI, ELConceptDescription> existentialRestriction2 : concept2.getExistentialRestrictions())
069//        if (existentialRestriction1.x().equals(existentialRestriction2.x())) {
070//          commonRestrictions.add(
071//              new Pair<IRI, ELConceptDescription>(
072//                  existentialRestriction1.x(),
073//                  _of(existentialRestriction1.y(), existentialRestriction2.y())));
074//        }
075//    final ELConceptDescription lcs = new ELConceptDescription(commonNames, commonRestrictions);
076////    System.out.println("lcs( " + concept1 + " , " + concept2 + " ) = " + lcs);
077//    lcsCache.put(_concepts, lcs);
078//    return lcs.clone();
079//  }
080//
081//  protected static final ELConceptDescription _of(ELConceptDescription... concepts) {
082////    final Set<ELNormalForm> _concepts = Sets.newHashSet(concepts);
083////    final ELNormalForm _lcs = lcsCache.get(_concepts);
084////    if (_lcs != null)
085////      return _lcs;
086////    if (concepts.length == 0)
087////      return new ELNormalForm();
088////    if (concepts.length == 1)
089////      return concepts[0];
090////    if (concepts.length == 2)
091////      return _of(concepts[0], concepts[1]);
092//    return _of(Arrays.asList(concepts));
093//  }
094//
095//  protected static final ELConceptDescription _of(Collection<ELConceptDescription> concepts) {
096//    final Set<ELConceptDescription> _concepts = Sets.newHashSet(concepts);
097//    final ELConceptDescription _lcs = lcsCache.get(_concepts);
098//    if (_lcs != null)
099//      return _lcs.clone();
100//    if (concepts.isEmpty())
101//      return new ELConceptDescription();
102//    final Iterator<ELConceptDescription> it = concepts.iterator();
103//    if (concepts.size() == 1)
104//      return it.next();
105//    if (concepts.size() == 2) {
106//      final ELConceptDescription lcs = _of(it.next(), it.next());
107//      lcsCache.put(_concepts, lcs);
108//      return lcs;
109//    }
110//    ELConceptDescription lcs = it.next();
111//    while (it.hasNext())
112//      lcs = _of(lcs, it.next());
113//    lcsCache.put(_concepts, lcs);
114//    return lcs.clone();
115//  }
116
117  public static final ELConceptDescription lcs(final ELConceptDescription C, final ELConceptDescription D) {
118    return lcs(Sets.newHashSet(C, D));
119  }
120
121  public static final ELConceptDescription lcs(final Set<ELConceptDescription> Cs) {
122    Cs.parallelStream().forEach(ELConceptDescription::reduce);
123    final Set<ELConceptDescription> Ds = Collections3.representatives(Cs, (X, Y) -> X.isEquivalentTo(Y));
124    if (Ds.isEmpty())
125      return ELConceptDescription.bot();
126    else if (Ds.size() == 1)
127      return Ds.iterator().next().clone();
128    else
129      return lcsOfMutuallyIncomparable(Ds);
130  }
131
132  public static final ELConceptDescription
133      lcsOfMutuallyIncomparable(final ELConceptDescription C, final ELConceptDescription D) {
134    return lcsOfMutuallyIncomparable(Sets.newHashSet(C, D));
135  }
136
137  public static final ELConceptDescription lcsOfMutuallyIncomparable(final Set<ELConceptDescription> Ds) {
138    final ELConceptDescription lcs = new ELConceptDescription();
139    final Iterator<ELConceptDescription> it = Ds.iterator();
140    final ELConceptDescription D = it.next();
141    it.remove();
142    final Set<IRI> commonConceptNames = D
143        .getConceptNames()
144        .parallelStream()
145        .filter(A -> Ds.parallelStream().map(ELConceptDescription::getConceptNames).allMatch(As -> As.contains(A)))
146        .collect(Collectors.toSet());
147    lcs.getConceptNames().addAll(commonConceptNames);
148    final Set<IRI> commonRoleNames = D
149        .getExistentialRestrictions()
150        .keySet()
151        .parallelStream()
152        .filter(
153            r -> Ds.parallelStream().map(ELConceptDescription::getExistentialRestrictions).allMatch(
154                ERs -> ERs.keySet().parallelStream().anyMatch(r::equals)))
155        .collect(Collectors.toSet());
156    Ds.add(D);
157    commonRoleNames
158        .parallelStream()
159        .map(
160            r -> Pair.of(
161                r,
162                Sets
163                    .cartesianProduct(
164                        Ds
165                            .parallelStream()
166                            .map(ELConceptDescription::getExistentialRestrictions)
167                            .map(m -> m.get(r))
168                            .map(HashSet::new)
169                            .collect(Collectors.toList()))
170                    .parallelStream()
171                    .map(HashSet::new)
172                    .map(ELLeastCommonSubsumer::lcsOfMutuallyIncomparable)
173                    .map(ELConceptDescription::reduce)
174                    .collect(Collectors.toSet())))
175        .sequential()
176        .forEach(p -> lcs.getExistentialRestrictions().putAll(p.x(), p.y()));;
177    return lcs.clone().reduce();
178  }
179
180  public static final OWLClassExpression of(final OWLClassExpression concept1, final OWLClassExpression concept2) {
181    return ELLeastCommonSubsumer
182        .lcs(ELConceptDescription.of(concept1), ELConceptDescription.of(concept2))
183        .toOWLClassExpression();
184  }
185
186  public static final OWLClassExpression of(final OWLClassExpression... concepts) {
187    if (concepts.length == 0)
188      return df.getOWLThing();
189    if (concepts.length == 1)
190      return concepts[0];
191    if (concepts.length == 2)
192      return of(concepts[0], concepts[1]);
193    return of(Arrays.asList(concepts));
194  }
195
196  public static final OWLClassExpression of(final Collection<OWLClassExpression> concepts) {
197    if (concepts.isEmpty())
198      return df.getOWLThing();
199    final Iterator<OWLClassExpression> it = concepts.iterator();
200    if (concepts.size() == 1)
201      return it.next();
202    if (concepts.size() == 2)
203      return of(it.next(), it.next());
204    OWLClassExpression lcs = it.next();
205    while (it.hasNext())
206      lcs = of(lcs, it.next());
207    return lcs;
208  }
209
210//if (concept1.isOWLNothing())
211//  return concept2;
212//if (concept2.isOWLNothing())
213//  return concept1;
214//if (concept1.isOWLThing())
215//  return concept1;
216//if (concept2.isOWLThing())
217//  return concept2;
218//if (concept1 instanceof OWLClass)
219//  if (concept2 instanceof OWLClass)
220//    if (((OWLClass) concept1).getIRI().equals(((OWLClass) concept2).getIRI()))
221//      return concept1;
222//    else
223//      return df.getOWLThing();
224//  else if (concept2 instanceof OWLObjectSomeValuesFrom)
225//    return df.getOWLThing();
226//  else if (concept2 instanceof OWLObjectIntersectionOf)
227//    if (((OWLObjectIntersectionOf) concept2).asConjunctSet().contains(concept1))
228//      return concept1;
229//    else
230//      return df.getOWLThing();
231//  else
232//    throw new ELSyntaxException();
233//else if (concept1 instanceof OWLObjectSomeValuesFrom)
234//  if (concept2 instanceof OWLClass)
235//    return df.getOWLThing();
236//  else if (concept2 instanceof OWLObjectSomeValuesFrom)
237//    if (((OWLObjectSomeValuesFrom) concept1).getProperty().equals(
238//        ((OWLObjectSomeValuesFrom) concept2).getProperty()))
239//      return df.getOWLObjectSomeValuesFrom(
240//          ((OWLObjectSomeValuesFrom) concept1).getProperty(),
241//          of(((OWLObjectSomeValuesFrom) concept1).getFiller(), ((OWLObjectSomeValuesFrom) concept2).getFiller()));
242//    else
243//      return df.getOWLThing();
244//  else if (concept2 instanceof OWLObjectIntersectionOf)
245//    return null;
246//  else
247//    return df.getOWLThing();
248//else if (concept1 instanceof OWLObjectIntersectionOf)
249//
250//  return df.getOWLThing();
251
252}