Optimize OWLOntology#referencingAxioms(OWLPrimitive)
Closed this issue · 1 comments
sszuev commented
Current implementation based on searching over existing axiom caches is extremely inefficient.
The graph optimized way is, as usual, much more faster.
Here is statistic:
START::: 2020-03-03T17:18:20.695Z
========================================
TEST PIZZA:::: CLASSES=100 ||| AXIOMS=945 |||| iter = 10
DEF::: 0.0431 s.
GRH::: 0.07750000000000003 s.
========================================
TEST FAMILY:::: CLASSES=58 ||| AXIOMS=2845 |||| iter = 10
DEF::: 0.020599999999999997 s.
GRH::: 0.029400000000000003 s.
========================================
TEST PS:::: CLASSES=6038 ||| AXIOMS=38872 |||| iter = 5
DEF::: 8.541 s.
GRH::: 0.183 s.
========================================
TEST GALEN:::: CLASSES=23142 ||| AXIOMS=96463 |||| iter = 1
DEF::: 1484.803 s.
GRH::: 4.399 s.
========================================
TEST HP:::: CLASSES=15984 ||| AXIOMS=143855 |||| iter = 1
DEF::: 516.407 s.
GRH::: 3.229 s.
========================================
TEST TTO:::: CLASSES=38705 ||| AXIOMS=336291 |||| iter = 1
DEF::: 655.279 s.
GRH::: 1.467 s.
========================================
TEST GO:::: CLASSES=49797 ||| AXIOMS=556475 |||| iter = 1
DEF::: 4839.628 s.
GRH::: 6.022 s.
TOTAL::: PT2H6M40.32S
The code (for the ont-api.wiki project, AxiomReferencesTmp.java) follows:
private static final Set<Class<? extends OntClass.CardinalityRestrictionCE<?, ?>>> OBJECT_CARDINALITY_TYPES =
Stream.of(OntClass.ObjectMaxCardinality.class,
OntClass.ObjectMinCardinality.class, OntClass.ObjectCardinality.class).collect(Collectors.toSet());
private static final Set<AxiomTranslator<? extends OWLAxiom>> CLASS_TRANSLATORS = OWLContentType.all()
.filter(x -> x.hasComponent(OWLComponentType.CLASS))
.map(OWLContentType::getAxiomType)
.map(AxiomParserProvider::get).collect(Collectors.toSet());
public static void main(String... args) throws Exception {
Instant s = Instant.now();
System.out.println("START::: " + s);
testReferences(TestData.PIZZA, 10);
testReferences(TestData.FAMILY, 10);
testReferences(TestData.PS, 5);
testReferences(TestData.GALEN, 1);
testReferences(TestData.HP, 1);
testReferences(TestData.TTO, 1);
testReferences(TestData.GO, 1);
System.out.println("TOTAL::: " + Duration.between(s, Instant.now()));
}
private static void testReferences(TestData data, int num) throws Exception {
System.out.println("========================================");
OntologyManager m = OntManagers.createONT();
Ontology o = m.loadOntologyFromOntologyDocument(data.getDocumentSource());
Set<OWLClass> classes = o.classesInSignature().collect(Collectors.toSet());
System.out.printf("TEST %s:::: CLASSES=%d ||| AXIOMS=%d |||| iter = %d%n",
data, classes.size(), o.getAxiomCount(), num);
long count1 = measure("DEF", num, () -> classes.stream().flatMap(o::referencingAxioms));
long count2 = measure("GRH", num, () -> classes.stream().flatMap(x -> referencingAxioms(o, x)));
if (count1 != count2) throw new IllegalStateException();
}
private static long measure(String pref, int num, Supplier<Stream<?>> get) {
long count = 0;
double d = 0;
for (int i = 0; i < num; i++) {
Instant s = Instant.now();
count += get.get().distinct().count();
d += getDurationInSeconds(Duration.between(s, Instant.now()));
}
count /= num;
d /= num;
System.out.println(pref + "::: " + d + " s.");
return count;
}
public static double getDurationInSeconds(Duration d) {
return (double) d.getSeconds() + d.getNano() / 1_000_000_000d;
}
public static Stream<OWLAxiom> referencingAxioms(Ontology o, OWLClass c) {
OntModel m = o.asGraphModel();
OntClass clazz = m.getOntClass(c.getIRI().getIRIString());
Stream<OntStatement> candidates = Stream.concat(m.statements(clazz, null, null),
m.statements(null, null, clazz).flatMap(AxiomReferencesTmp::roots));
if (OWL.Thing.equals(clazz)) {
candidates = Stream.concat(candidates, specialForThing(m).flatMap(AxiomReferencesTmp::roots));
}
return candidates.flatMap(s -> translators(s).map(x -> x.toAxiom(s).getOWLObject()));
}
private static Stream<OntStatement> specialForThing(OntModel m) {
return Stream.of(OWL.cardinality, OWL.maxCardinality, OWL.minCardinality)
.flatMap(p -> m.statements(null, p, null))
.filter(AxiomReferencesTmp::isObjectRestriction);
}
private static boolean isObjectRestriction(OntStatement s) {
return OBJECT_CARDINALITY_TYPES.stream().anyMatch(t -> s.getSubject().canAs(t));
}
private static Stream<? extends AxiomTranslator<? extends OWLAxiom>> translators(OntStatement s) {
return CLASS_TRANSLATORS.stream().filter(x -> x.testStatement(s));
}
private static Stream<OntStatement> roots(OntStatement s) {
return roots(s.getModel(), s, new HashSet<>());
}
private static Stream<OntStatement> roots(OntModel m, OntStatement st, Set<OntStatement> seen) {
Resource s = st.getSubject();
if (s.isURIResource()) {
return Stream.of(st);
}
Set<OntStatement> set = m.statements(null, null, s).filter(seen::add).collect(Collectors.toSet());
if (set.isEmpty()) return Stream.of(st);
return set.stream().flatMap(x -> roots(m, x, seen));
}
sszuev commented
done