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}