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}