001package conexp.fx.core.dl; 002 003import java.util.Collections; 004import java.util.HashSet; 005import java.util.Set; 006import java.util.concurrent.Executors; 007import java.util.concurrent.atomic.AtomicInteger; 008import java.util.function.Predicate; 009import java.util.stream.Collectors; 010 011import org.semanticweb.owlapi.model.IRI; 012 013import com.google.common.collect.Sets; 014 015import conexp.fx.core.algorithm.nextclosures.NextClosures2; 016import conexp.fx.core.collections.Collections3; 017import conexp.fx.core.context.Implication; 018import conexp.fx.core.math.DualClosureOperator; 019import conexp.fx.core.math.SetClosureOperator; 020 021/*- 022 * #%L 023 * Concept Explorer FX 024 * %% 025 * Copyright (C) 2010 - 2019 Francesco Kriegel 026 * %% 027 * This program is free software: you can redistribute it and/or modify 028 * it under the terms of the GNU General Public License as 029 * published by the Free Software Foundation, either version 3 of the 030 * License, or (at your option) any later version. 031 * 032 * This program is distributed in the hope that it will be useful, 033 * but WITHOUT ANY WARRANTY; without even the implied warranty of 034 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 035 * GNU General Public License for more details. 036 * 037 * You should have received a copy of the GNU General Public 038 * License along with this program. If not, see 039 * <http://www.gnu.org/licenses/gpl-3.0.html>. 040 * #L% 041 */ 042 043public final class ELAxiomatizer { 044 045 public static final <I> ELAxiomatizer from(final Signature sigma, final ELInterpretation2<I> i, final int roleDepth) { 046 return new ELAxiomatizer(sigma, roleDepth, true, __ -> false, DualClosureOperator.fromInterpretation(i, roleDepth)); 047 } 048 049 public static final <I> ELAxiomatizer 050 from(final Signature sigma, final ELInterpretation2<I> i, final ELTBox t, final int roleDepth) { 051 return new ELAxiomatizer( 052 sigma, 053 roleDepth, 054 true, 055 __ -> false, 056 DualClosureOperator 057 .infimum(DualClosureOperator.fromInterpretation(i, roleDepth), DualClosureOperator.fromTBox(t, roleDepth))); 058 } 059 060 private final Signature sigma; 061 private final int roleDepth; 062 private final boolean withBot; 063 private final Predicate<ELConceptDescription> hasEmptySupport; 064 private final DualClosureOperator<ELConceptDescription> clop; 065 private Set<ELConceptDescription> closures; 066 private final Set<ELConceptDescription> visited; 067 private final Set<ELConceptDescription> attributes; 068 private SetClosureOperator<ELConceptDescription> setClop; 069 070 public ELAxiomatizer( 071 final Signature sigma, 072 final int roleDepth, 073 final boolean withBot, 074 final Predicate<ELConceptDescription> hasEmptySupport, 075 final DualClosureOperator<ELConceptDescription> clop) { 076 super(); 077 this.sigma = sigma; 078 this.roleDepth = roleDepth; 079 this.withBot = withBot; 080 this.hasEmptySupport = hasEmptySupport; 081 this.clop = clop; 082 this.closures = Sets.newConcurrentHashSet(); 083 this.visited = Sets.newConcurrentHashSet(); 084 this.attributes = new HashSet<>(); 085 } 086 087 public final void initialize() { 088 computeAttributeSet(); 089 setClop = set -> { 090 final ELConceptDescription dlClosure = clop.closure(ELConceptDescription.conjunction(set).reduce()).reduce(); 091 return attributes.parallelStream().filter(dlClosure::isSubsumedBy).collect(Collectors.toSet()); 092 }; 093 } 094 095 private final void computeAttributeSet() { 096 System.out.println("Computing all closures..."); 097 findClosuresBelow(ELConceptDescription.top()); 098 closures = Collections3.representatives(closures, ELConceptDescription::equivalent); 099 System.out.println(" " + closures.size() + " closures"); 100 System.out.println("Constructing attributes..."); 101 if (withBot) 102 attributes.add(ELConceptDescription.bot()); 103 for (IRI A : sigma.getConceptNames()) 104 attributes.add(ELConceptDescription.conceptName(A)); 105 for (IRI r : sigma.getRoleNames()) 106 for (ELConceptDescription D : closures) 107 attributes.add(ELConceptDescription.existentialRestriction(r, D)); 108 System.out.println(" " + attributes.size() + " attributes"); 109 System.out.println(attributes); 110 } 111 112 private AtomicInteger num = new AtomicInteger(); 113 114 private final void findClosuresBelow(final ELConceptDescription c) { 115 if (!visited.contains(c)) 116 try { 117 visited.add(c); 118 System.out.println("Searching closures below " + c); 119 final ELConceptDescription closure = clop.closure(c); 120 closure.restrictTo(roleDepth - 1); 121 closures.add(closure); 122 System.out.println("closure " + num.incrementAndGet() + " " + closure); 123 for (final ELConceptDescription lower : closure.lowerNeighborsB(sigma)) 124 if (lower.roleDepth() < roleDepth) 125 findClosuresBelow(lower); 126 } catch (IllegalArgumentException __) {} 127 } 128 129 public final ELTBox compute() { 130 System.out.println("Generating background knowledge..."); 131 final Set<Implication<Object, ELConceptDescription>> backgroundKnowledge = Sets.newConcurrentHashSet(); 132 attributes.parallelStream().forEach(X -> attributes.parallelStream().forEach(Y -> { 133 if (X.isSubsumedBy(Y)) 134 backgroundKnowledge.add(new Implication<Object, ELConceptDescription>(X, Y)); 135 })); 136 System.out.println("Starting axiomatization..."); 137 final Set<Implication<Object, ELConceptDescription>> implications = NextClosures2 138 .compute( 139 attributes, 140 setClop, 141 __ -> Collections.emptySet(), 142 set -> hasEmptySupport.test(ELConceptDescription.conjunction(set)), 143 Executors.newWorkStealingPool(), 144 __ -> {}, 145 implication -> { 146 System.out.println(implication); 147 final ELConceptDescription subsumee = ELConceptDescription.conjunction(implication.getPremise()).reduce(); 148 final ELConceptDescription subsumer = 149 ELConceptDescription.conjunction(implication.getConclusion()).reduce(); 150 final ELConceptInclusion ci = new ELConceptInclusion(subsumee, subsumer.without(subsumee)); 151 if (!ci.isTautological()) 152 System.out.println(ci); 153 else 154 System.out.println("tautology"); 155 }, 156 System.out::println, 157 __ -> {}, 158 () -> false, 159 backgroundKnowledge) 160 .second(); 161 final ELTBox result = new ELTBox(); 162 for (Implication<Object, ELConceptDescription> implication : implications) { 163 implication.getConclusion().removeAll(implication.getPremise()); 164 final ELConceptDescription subsumee = ELConceptDescription.conjunction(implication.getPremise()).reduce(); 165 final ELConceptDescription subsumer = ELConceptDescription.conjunction(implication.getConclusion()).reduce(); 166 final ELConceptInclusion ci = new ELConceptInclusion(subsumee, subsumer.without(subsumee)); 167 if (!ci.isTautological()) 168 result.getConceptInclusions().add(ci); 169 } 170 return result; 171 } 172 173 public static void main(String[] args) { 174// foo(); 175 bar(); 176 } 177 178 private static void foo() { 179 final Signature sigma = new Signature(IRI.create("foo")); 180 sigma.addConceptNames("A", "B", "C"); 181 sigma.addRoleNames("r"); 182 final ELTBox t1 = new ELTBox(); 183 t1.getConceptInclusions().add(ELConceptInclusion.parse("A", "exists r. B")); 184 t1.getConceptInclusions().add(ELConceptInclusion.parse("B", "exists r. B")); 185 final ELTBox t2 = new ELTBox(); 186 t2.getConceptInclusions().add(ELConceptInclusion.parse("A", "exists r. C")); 187 t2.getConceptInclusions().add(ELConceptInclusion.parse("C", "exists r. C")); 188 for (int d = 0; d < 5; d++) { 189 final DualClosureOperator<ELConceptDescription> clop = 190 DualClosureOperator.infimum(DualClosureOperator.fromTBox(t1, d), DualClosureOperator.fromTBox(t2, d)); 191 final ELAxiomatizer axiomatizer = new ELAxiomatizer(sigma, d, true, __ -> false, clop); 192 axiomatizer.initialize(); 193 final ELTBox base = axiomatizer.compute(); 194 System.out.println("d=" + d); 195 System.out.println(base); 196 System.out.println(); 197 } 198 } 199 200 private static void bar() { 201 // This is the toy example from my DAM 2019 paper. 202 final Signature sigma = new Signature(IRI.create("bar")); 203 sigma.addConceptNames("Person", "Car", "Wheel"); 204 sigma.addRoleNames("child"); 205 final ELInterpretation2<Integer> i = new ELInterpretation2<>(); 206 i.add(0, "Car"); 207 i.add(1, "Wheel"); 208 i.add(2, "Person"); 209 i.add(3, "Person"); 210 i.add(0, "child", 1); 211 i.add(2, "child", 3); 212 final ELTBox t = new ELTBox(); 213 t.getConceptInclusions().add(ELConceptInclusion.parse("exists child. Top", "Person")); 214 t.getConceptInclusions().add(ELConceptInclusion.parse("Person and Car", "Bot")); 215 System.out.println(t); 216 for (int d = 0; d < 5; d++) { 217// final DualClosureOperator<ELConceptDescription> clop = DualClosureOperator.fromInterpretation(i, d); 218 final DualClosureOperator<ELConceptDescription> clop = DualClosureOperator 219 .supremum(DualClosureOperator.fromInterpretation(i, d), DualClosureOperator.fromTBox(t, d)); 220 System.out.println("Car has closure " + clop.closure(ELConceptDescription.parse("Car"))); 221 final ELAxiomatizer axiomatizer = new ELAxiomatizer(sigma, d, true, __ -> false, clop); 222 axiomatizer.initialize(); 223 final ELTBox base = axiomatizer.compute(); 224 System.out.println("d=" + d); 225 System.out.println(base); 226 System.out.println(); 227 } 228 } 229 230 private static void baz() { 231 232 } 233 234}