Skip to content

Commit 4298d16

Browse files
committed
ont-api: add OWLSameIndividualAxiom implementation + fix and add tests (issue #2)
1 parent 7cd802e commit 4298d16

12 files changed

+445
-90
lines changed

src/main/java/com/github/owlcs/ontapi/internal/axioms/AbstractNaryTranslator.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.jena.rdf.model.Statement;
2727
import org.apache.jena.util.iterator.ExtendedIterator;
2828
import org.semanticweb.owlapi.model.*;
29+
import org.semanticweb.owlapi.util.OWLAPIStreamUtils;
2930
import org.slf4j.Logger;
3031
import org.slf4j.LoggerFactory;
3132

@@ -120,6 +121,9 @@ protected NaryAxiomImpl(Object subject, String predicate, Object object, Supplie
120121

121122
/**
122123
* Returns the number of components.
124+
* For single-triple axioms (i.e. a with predicate such as {@code owl:sameAs}, {@code owl:equivalentClass})
125+
* the method returns {@code 2}.
126+
* Only n-ary axioms which are based on {@link OntDisjoint} resource can different members count.
123127
*
124128
* @return long
125129
*/
@@ -228,6 +232,19 @@ boolean testSameContent(ONTStatementImpl other) {
228232
}
229233
return false;
230234
}
235+
236+
/**
237+
* Lists {@link T}s retrieved from the axiom internals.
238+
*
239+
* @param visitor {@link OWLPairwiseVisitor}, a visitor to apply to all pairwise elements in this axiom;
240+
* pairs are ordered, i.e., (i, j) and (j, i) will be considered. (i,i) is skipped, not {@code null}
241+
* @param <T> the type returned by the {@code visitor}
242+
* @return a {@code Stream} of {@link T}s
243+
* @see OWLNaryAxiom#walkAllPairwise(OWLPairwiseVisitor)
244+
*/
245+
protected <T> Stream<T> fromPairs(OWLPairwiseVisitor<T, M> visitor) {
246+
return OWLAPIStreamUtils.allPairs(operands()).map(v -> visitor.visit(v.i, v.j)).filter(Objects::nonNull);
247+
}
231248
}
232249

233250
/**
@@ -308,7 +325,7 @@ public final boolean canContainNamedClasses() {
308325

309326
@Override
310327
public final boolean canContainClassExpressions() {
311-
return true;
328+
return false;
312329
}
313330

314331
@Override
@@ -358,13 +375,14 @@ abstract static class ClassOrIndividualNaryAxiomImpl<A extends OWLNaryAxiom<M>,
358375
* @param a - {@link M}, the first operand, not {@code null}
359376
* @param b - {@link M}, the second operand, not {@code null}
360377
* @return {@link OWLSubClassOfAxiom}
378+
* @see NaryAxiomImpl#fromPairs(OWLPairwiseVisitor)
361379
*/
362380
@FactoryAccessor
363381
protected abstract OWLSubClassOfAxiom createSubClassOf(M a, M b);
364382

365383
@FactoryAccessor
366384
@Override
367-
public final Collection<OWLSubClassOfAxiom> asOWLSubClassOfAxioms() {
385+
public Collection<OWLSubClassOfAxiom> asOWLSubClassOfAxioms() {
368386
return walkAllPairwise((a, b) -> createSubClassOf(eraseModel(a), eraseModel(b)));
369387
}
370388
}

src/main/java/com/github/owlcs/ontapi/internal/axioms/EquivalentClassesTranslator.java

+21-5
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,14 @@
3636

3737
/**
3838
* A translator that provides {@link OWLEquivalentClassesAxiom} implementations.
39-
* Base class {@link AbstractNaryTranslator}
39+
* Base class {@link AbstractNaryTranslator}.
4040
* Example of ttl:
4141
* <pre>{@code
4242
* pizza:SpicyTopping owl:equivalentClass [ a owl:Class; owl:intersectionOf ( pizza:PizzaTopping [a owl:Restriction; owl:onProperty pizza:hasSpiciness; owl:someValuesFrom pizza:Hot] )] ;
4343
* }
4444
* </pre>
4545
* <p>
4646
* Created by @szuev on 29.09.2016.
47-
*
48-
* @see OWLEquivalentClassesAxiom
4947
*/
5048
public class EquivalentClassesTranslator extends AbstractNaryTranslator<OWLEquivalentClassesAxiom, OWLClassExpression, OntCE> {
5149

@@ -168,6 +166,10 @@ protected SimpleImpl(Object s, String p, Object o, Supplier<OntGraphModel> m) {
168166
super(s, p, o, m);
169167
}
170168

169+
private static boolean isNonBuiltin(String uri) {
170+
return !uri.equals(OWL.Thing.getURI()) && !uri.equals(OWL.Nothing.getURI());
171+
}
172+
171173
@Override
172174
protected boolean sameContent(ONTStatementImpl other) {
173175
return other instanceof SimpleImpl && isReverseTriple((SimpleImpl) other);
@@ -193,6 +195,21 @@ public Stream<Triple> triples() {
193195
};
194196
}
195197

198+
@Override
199+
public boolean containsNamedEquivalentClass() {
200+
return isNonBuiltin((String) subject) || isNonBuiltin((String) object);
201+
}
202+
203+
@Override
204+
public boolean containsOWLNothing() {
205+
return hasURIResource(OWL.Nothing);
206+
}
207+
208+
@Override
209+
public boolean containsOWLThing() {
210+
return hasURIResource(OWL.Thing);
211+
}
212+
196213
@SuppressWarnings("unchecked")
197214
@Override
198215
public Set<OWLClass> getNamedClassSet() {
@@ -213,8 +230,7 @@ public Set<OWLEntity> getSignatureSet() {
213230

214231
@Override
215232
public boolean containsNamedClass(OWLClass clazz) {
216-
String uri = ONTEntityImpl.getURI(clazz);
217-
return subject.equals(uri) || object.equals(uri);
233+
return hasURIResource(ONTEntityImpl.getURI(clazz));
218234
}
219235

220236
@Override

src/main/java/com/github/owlcs/ontapi/internal/axioms/SameIndividualTranslator.java

+207-16
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,30 @@
1414

1515
package com.github.owlcs.ontapi.internal.axioms;
1616

17-
import org.apache.jena.rdf.model.Property;
18-
import org.semanticweb.owlapi.model.OWLAnnotation;
19-
import org.semanticweb.owlapi.model.OWLIndividual;
20-
import org.semanticweb.owlapi.model.OWLSameIndividualAxiom;
21-
import com.github.owlcs.ontapi.internal.InternalConfig;
22-
import com.github.owlcs.ontapi.internal.InternalObjectFactory;
23-
import com.github.owlcs.ontapi.internal.ONTObject;
24-
import com.github.owlcs.ontapi.internal.ONTWrapperImpl;
17+
import com.github.owlcs.ontapi.DataFactory;
18+
import com.github.owlcs.ontapi.internal.*;
19+
import com.github.owlcs.ontapi.internal.objects.FactoryAccessor;
20+
import com.github.owlcs.ontapi.internal.objects.ONTEntityImpl;
21+
import com.github.owlcs.ontapi.internal.objects.ONTStatementImpl;
22+
import com.github.owlcs.ontapi.jena.model.OntGraphModel;
2523
import com.github.owlcs.ontapi.jena.model.OntIndividual;
2624
import com.github.owlcs.ontapi.jena.model.OntStatement;
2725
import com.github.owlcs.ontapi.jena.vocabulary.OWL;
26+
import org.apache.jena.graph.Triple;
27+
import org.apache.jena.rdf.model.Property;
28+
import org.semanticweb.owlapi.model.*;
2829

30+
import java.util.Arrays;
2931
import java.util.Collection;
32+
import java.util.Set;
33+
import java.util.function.BiFunction;
34+
import java.util.function.Supplier;
35+
import java.util.stream.Collectors;
36+
import java.util.stream.Stream;
3037

3138
/**
32-
* base class {@link AbstractNaryTranslator}
33-
* example:
39+
* A translator that provides {@link OWLSameIndividualAxiom} implementations.
40+
* Example:
3441
* <pre>{@code
3542
* :indi1 owl:sameAs :indi2, :indi3 .
3643
* }</pre>
@@ -39,7 +46,8 @@
3946
*
4047
* @see OWLSameIndividualAxiom
4148
*/
42-
public class SameIndividualTranslator extends AbstractNaryTranslator<OWLSameIndividualAxiom, OWLIndividual, OntIndividual> {
49+
public class SameIndividualTranslator
50+
extends AbstractNaryTranslator<OWLSameIndividualAxiom, OWLIndividual, OntIndividual> {
4351

4452
@Override
4553
public Property getPredicate() {
@@ -53,14 +61,197 @@ Class<OntIndividual> getView() {
5361

5462
@Override
5563
public ONTObject<OWLSameIndividualAxiom> toAxiom(OntStatement statement,
56-
InternalObjectFactory reader,
64+
Supplier<OntGraphModel> model,
65+
InternalObjectFactory factory,
5766
InternalConfig config) {
58-
ONTObject<? extends OWLIndividual> a = reader.getIndividual(statement.getSubject(getView()));
59-
ONTObject<? extends OWLIndividual> b = reader.getIndividual(statement.getObject().as(getView()));
60-
Collection<ONTObject<OWLAnnotation>> annotations = reader.getAnnotations(statement, config);
61-
OWLSameIndividualAxiom res = reader.getOWLDataFactory()
67+
return AxiomImpl.create(statement, model, factory, config);
68+
}
69+
70+
@Override
71+
public ONTObject<OWLSameIndividualAxiom> toAxiom(OntStatement statement,
72+
InternalObjectFactory factory,
73+
InternalConfig config) {
74+
ONTObject<? extends OWLIndividual> a = factory.getIndividual(statement.getSubject(getView()));
75+
ONTObject<? extends OWLIndividual> b = factory.getIndividual(statement.getObject().as(getView()));
76+
Collection<ONTObject<OWLAnnotation>> annotations = factory.getAnnotations(statement, config);
77+
OWLSameIndividualAxiom res = factory.getOWLDataFactory()
6278
.getOWLSameIndividualAxiom(a.getOWLObject(), b.getOWLObject(), ONTObject.toSet(annotations));
6379
return ONTWrapperImpl.create(res, statement).append(annotations).append(a).append(b);
6480
}
6581

82+
/**
83+
* @see com.github.owlcs.ontapi.owlapi.axioms.OWLSameIndividualAxiomImpl
84+
*/
85+
public abstract static class AxiomImpl extends IndividualNaryAxiomImpl<OWLSameIndividualAxiom>
86+
implements OWLSameIndividualAxiom {
87+
88+
protected AxiomImpl(Triple t, Supplier<OntGraphModel> m) {
89+
this(strip(t.getSubject()), t.getPredicate().getURI(), strip(t.getObject()), m);
90+
}
91+
92+
protected AxiomImpl(Object s, String p, Object o, Supplier<OntGraphModel> m) {
93+
super(s, p, o, m);
94+
}
95+
96+
/**
97+
* Creates an {@link ONTObject} container, that is also {@link OWLSameIndividualAxiom}.
98+
*
99+
* @param statement {@link OntStatement}, not {@code null}
100+
* @param model {@link OntGraphModel} provider, not {@code null}
101+
* @param factory {@link InternalObjectFactory}, not {@code null}
102+
* @param config {@link InternalConfig}, not {@code null}
103+
* @return {@link AxiomImpl}
104+
*/
105+
public static AxiomImpl create(OntStatement statement,
106+
Supplier<OntGraphModel> model,
107+
InternalObjectFactory factory,
108+
InternalConfig config) {
109+
return WithManyObjects.create(statement, model,
110+
SimpleImpl.FACTORY, ComplexImpl.FACTORY, SET_HASH_CODE, factory, config);
111+
}
112+
113+
@Override
114+
protected final long count() {
115+
return 2;
116+
}
117+
118+
@Override
119+
public boolean containsAnonymousIndividuals() {
120+
return individuals().anyMatch(OWLIndividual::isAnonymous);
121+
}
122+
123+
@FactoryAccessor
124+
@Override
125+
protected OWLSameIndividualAxiom createAxiom(Collection<OWLIndividual> members,
126+
Collection<OWLAnnotation> annotations) {
127+
return getDataFactory().getOWLSameIndividualAxiom(members,
128+
annotations == null ? NO_ANNOTATIONS : annotations);
129+
}
130+
131+
@FactoryAccessor
132+
@Override
133+
protected OWLSubClassOfAxiom createSubClassOf(OWLIndividual a, OWLIndividual b) {
134+
DataFactory df = getDataFactory();
135+
return df.getOWLSubClassOfAxiom(df.getOWLObjectOneOf(a), df.getOWLObjectOneOf(b));
136+
}
137+
138+
@FactoryAccessor
139+
@Override
140+
public Collection<OWLSubClassOfAxiom> asOWLSubClassOfAxioms() { // OWL-API-impl returns a Set here
141+
return fromPairs((a, b) -> createSubClassOf(eraseModel(a), eraseModel(b))).collect(Collectors.toSet());
142+
}
143+
144+
/**
145+
* An {@link OWLSameIndividualAxiom} that has named classes as subject and object and has no annotations.
146+
*/
147+
protected static class SimpleImpl extends AxiomImpl implements Simple<OWLIndividual> {
148+
149+
private static final BiFunction<Triple, Supplier<OntGraphModel>, SimpleImpl> FACTORY = SimpleImpl::new;
150+
151+
protected SimpleImpl(Triple t, Supplier<OntGraphModel> m) {
152+
super(t, m);
153+
}
154+
155+
protected SimpleImpl(Object s, String p, Object o, Supplier<OntGraphModel> m) {
156+
super(s, p, o, m);
157+
}
158+
159+
@Override
160+
protected boolean sameContent(ONTStatementImpl other) {
161+
return other instanceof SimpleImpl && isReverseTriple((SimpleImpl) other);
162+
}
163+
164+
@Override
165+
protected AxiomImpl makeCopyWith(ONTObject<OWLSameIndividualAxiom> other) {
166+
if (other instanceof SimpleImpl) {
167+
Triple t = ((SimpleImpl) other).asTriple();
168+
return new SimpleImpl(subject, predicate, object, model) {
169+
170+
@Override
171+
public Stream<Triple> triples() {
172+
return Stream.concat(SimpleImpl.this.triples(), Stream.of(t));
173+
}
174+
};
175+
}
176+
return new SimpleImpl(subject, predicate, object, model) {
177+
@Override
178+
public Stream<Triple> triples() {
179+
return Stream.concat(SimpleImpl.this.triples(), other.triples());
180+
}
181+
};
182+
}
183+
184+
@Override
185+
public boolean containsAnonymousIndividuals() {
186+
return false;
187+
}
188+
189+
@SuppressWarnings("unchecked")
190+
@Override
191+
public Set<OWLNamedIndividual> getNamedIndividualSet() {
192+
return (Set<OWLNamedIndividual>) getOWLComponentsAsSet();
193+
}
194+
195+
@SuppressWarnings("unchecked")
196+
@Override
197+
public Set<OWLEntity> getSignatureSet() {
198+
return (Set<OWLEntity>) getOWLComponentsAsSet();
199+
}
200+
201+
@Override
202+
public boolean containsNamedIndividual(OWLNamedIndividual individual) {
203+
return hasURIResource(ONTEntityImpl.getURI(individual));
204+
}
205+
206+
@Override
207+
public boolean canContainAnonymousIndividuals() {
208+
return false;
209+
}
210+
}
211+
212+
/**
213+
* An {@link OWLSameIndividualAxiom}
214+
* that either has annotations or anonymous class expressions in subject or object positions.
215+
* It has a public constructor since it is more generic then {@link SimpleImpl}.
216+
*/
217+
public static class ComplexImpl extends AxiomImpl
218+
implements Complex<ComplexImpl, OWLIndividual> {
219+
220+
private static final BiFunction<Triple, Supplier<OntGraphModel>, ComplexImpl> FACTORY = ComplexImpl::new;
221+
protected final InternalCache.Loading<ComplexImpl, Object[]> content;
222+
223+
public ComplexImpl(Triple t, Supplier<OntGraphModel> m) {
224+
this(strip(t.getSubject()), t.getPredicate().getURI(), strip(t.getObject()), m);
225+
}
226+
227+
protected ComplexImpl(Object s, String p, Object o, Supplier<OntGraphModel> m) {
228+
super(s, p, o, m);
229+
this.content = createContentCache();
230+
}
231+
232+
@Override
233+
public InternalCache.Loading<ComplexImpl, Object[]> getContentCache() {
234+
return content;
235+
}
236+
237+
@Override
238+
protected boolean sameContent(ONTStatementImpl other) {
239+
return other instanceof ComplexImpl && Arrays.equals(getContent(), ((ComplexImpl) other).getContent());
240+
}
241+
242+
@Override
243+
protected ComplexImpl makeCopyWith(ONTObject<OWLSameIndividualAxiom> other) {
244+
ComplexImpl res = new ComplexImpl(subject, predicate, object, model) {
245+
@Override
246+
public Stream<Triple> triples() {
247+
return Stream.concat(ComplexImpl.this.triples(), other.triples());
248+
}
249+
};
250+
if (hasContent()) {
251+
res.putContent(getContent());
252+
}
253+
return res;
254+
}
255+
}
256+
}
66257
}

0 commit comments

Comments
 (0)