1:- module(owl_util,
    2          [is_en/1,
    3           enlabel_of/2,
    4           label_of/2,
    5           label_of/3,
    6
    7           literal_atom/2,
    8
    9           instantiated_class/1,
   10           declare_shacl_prefixes/0,
   11
   12           triple_axiom/2,
   13           triple_axiom/4,
   14           triple_axiom_annotation/3,
   15           triple_axiom_annotation/5,
   16           triple_axiom_annotations/4,
   17           triple_property_axiom_annotations/5,
   18           axiom_annotation/3,
   19
   20           owl_some/3,
   21           owl_all/3,
   22           owl_equivalent_class/2,
   23           owl_equivalent_class_asserted/2,
   24           owl_equivalent_class_asserted_symm/2,
   25           owl_equivalent_property_asserted_symm/2,
   26           thing_class/1,
   27           not_thing_class/1,
   28           deprecated/1,           
   29           subclass_of_some/3,
   30           subclass_cycle/1,
   31           owl_node_info/4,
   32           bnode_signature/2,
   33           
   34           eq_intersection_member/2,
   35           intersection_member/2,
   36           rdflist_member/2,
   37
   38           inferred_type/2,
   39
   40           class_genus/2,
   41           class_differentia/3,
   42
   43           owl_edge/3,
   44           owl_edge/4,
   45           owl_subgraph/4,
   46           owl_edge_ancestor/2,
   47           owl_edge_ancestor/3,
   48           
   49           extract_subontology/3,
   50
   51           quads_objects/2,
   52           quads_dict/2,
   53
   54           assert_named_individuals/0,
   55           assert_named_individuals_forall/0,
   56
   57           ensure_uri/2,
   58           ensure_curie/2,
   59           subsumed_prefix_namespace/4,
   60           
   61           common_ancestor/3,
   62           mrca/3,
   63           common_descendant/3,
   64           mrcd/3,
   65           egraph_common_ancestor/3,
   66           egraph_mrca/3,
   67
   68           simj_by_subclass/3,
   69           simj_by_subclass/5,
   70
   71           owl_assert_axiom/1,
   72           owl_assert_axiom/2,
   73           owl_assert_axiom/3,
   74           owl_assert_axiom_with_anns/3,
   75           owl_assert_axiom_with_anns/4
   76          ]).

OWL ontology wrapper

This module provides predicates for working with OWL ontologies. Although OWL ontologies can be accessed directly via rdf/3 triples, this can be quite a low level means of access, especially for ontologies employing constructs that map to multiple triples, including:

Note on use outside sparqlprog

Although this is distributed with sparqlprog, it can be used directly in conjunction with an in-memory triplestore.

*/

   92:- use_module(library(semweb/rdf11)).   93:- use_module(library(semweb/rdfs)).   94:- use_module(library(sparqlprog/ontologies/owl), []).   95
   96:- reexport(library(sparqlprog/ontologies/owl), [ label/2, subClassOf/2 ]).   97
   98:-op(300,xfy,some).   99:-op(300,xfy,all).  100
  101is_en(X) :- rdf_where(lang_matches(X,"en")).
  102
  103
  104enlabel_of(Label,X) :- label_of(Label,X,en).
 label_of(?Label, ?X) is nondet
  111label_of(Label,X) :- label_of(Label,X,_).
  112%label_of(Label,X) :- bind(str(Label),LabelStr),label_of(LabelStr,X,_).
  113
  114%! label_of(?Label, ?X, ?Lang) is nondet.
  115%
  116%
  117%
  118label_of(Label,X,Lang) :- rdf(X,rdfs:label,Label@Lang).
  119label_of(Label,X,_) :- rdf(X,rdfs:label,Label^^xsd:string).
  120%label_of(Label,X,Lang) :- rdf(X,rdfs:label,Lit), (Lit == Label@Lang ; Lit == Label^^xsd:string).
  121
  122instantiated_class(C) :-
  123        rdf(C,rdf:type,owl:'Class'),
  124        exists(rdf(_,rdf:type,C)).
  125
  126
  127declare_shacl_prefixes :-
  128        rdf(X,'http://www.w3.org/ns/shacl#prefix',Prefix1),
  129        rdf(X,'http://www.w3.org/ns/shacl#namespace', NS1),
  130        emulate_builtins:ensure_atom(Prefix1,Prefix),
  131        emulate_builtins:ensure_atom(NS1,NS),
  132        rdf_register_prefix(Prefix, NS),
  133        debug(owl_util,'Registered ~w ~w',[Prefix,NS]),
  134        fail.
  135declare_shacl_prefixes.
 triple_axiom(T, A) is nondet
as triple_axiom/4, first argument is triple(I,P1,J)
  141triple_axiom(rdf(I,P,J),A) :-
  142        triple_axiom(I,P,J,A).
 triple_axiom(?I, ?P, ?J, ?A) is nondet
  148triple_axiom(I,P,J,A) :-
  149        rdf(A,owl:annotatedSource,I),
  150        rdf(A,owl:annotatedProperty,P),
  151        rdf(A,owl:annotatedTarget,J).
  152
  153:- rdf_meta triple_axiom_annotation(r,r,o).
 triple_axiom_annotation(?T, ?P, ?V) is nondet
as triple_axiom_annotation/5, first argument is triple(I,P1,J)
  159triple_axiom_annotation(T,P,V) :-
  160        triple_axiom(T,A),
  161        axiom_annotation(A,P,V).
  162
  163:- rdf_meta triple_axiom_annotation(r,r,o,r,o).
 triple_axiom_annotation(?I, ?P1, ?J, ?P, ?V) is nondet
  169triple_axiom_annotation(I,P1,J,P,V) :-
  170        triple_axiom(I,P1,J,A),
  171        axiom_annotation(A,P,V).
  172
  173:- rdf_meta triple_axiom_annotations(r,r,o,-).
 triple_axiom_annotations(?I, ?P, ?J, ?L) is nondet
  179triple_axiom_annotations(I,P,J,L) :-
  180        rdf(I,P,J),
  181        findall(P1-V1,triple_axiom_annotation(I,P,J,P1,V1),L).
  182
  183:- rdf_meta triple_property_axiom_annotations(r,r,o,r,-).
 triple_property_axiom_annotations(?I, ?P, ?J, ?P1, ?L:list) is nondet
for a triple IPJ, yield all axiom annotation values for annotation property P1
  190triple_property_axiom_annotations(I,P,J,P1,L) :-
  191        rdf(I,P,J),
  192        findall(V1,triple_axiom_annotation(I,P,J,P1,V1),L).
 axiom_annotation(?Axiom, ?Property, ?Value) is nondet
Axiom is always a blank node

See https://www.w3.org/TR/owl2-primer/#Annotating_Axioms_and_Entities

  201axiom_annotation(A,P,V) :-
  202        rdf(A,P,V),
  203        rdf(A,rdf:type,owl:'Axiom'),
  204        P \= 'http://www.w3.org/2002/07/owl#annotatedProperty',
  205        P \= 'http://www.w3.org/2002/07/owl#annotatedSource',
  206        P \= 'http://www.w3.org/2002/07/owl#annotatedTarget',
  207        \+ ((P='http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
  208             V='http://www.w3.org/2002/07/owl#Axiom')).
  209
  210
  211
  212thing_class(owl:'Thing').
 not_thing_class(?X) is nondet
true unless X is owl:Thing
  218not_thing_class(X) :- X \= owl:'Thing'.
  219
  220
  221%! deprecated(?X) is nondet.
  222%
  223%    true if X has a owl:deprecated axiom with value true
  224%
  225deprecated(X) :- rdf(X,owl:deprecated,"true"^^xsd:boolean).
 owl_equivalent_class(?A, ?B) is nondet
inferred equivalent class between A and B, exploiting transitivity and symmetry
  233owl_equivalent_class(A,B) :- rdf_path(A,zeroOrMore( (owl:equivalentClass)| \(owl:equivalentClass)),B).
 owl_equivalent_class_asserted(?A, ?B) is nondet
only holds if the assertion is in the direction from A to B
  239owl_equivalent_class_asserted(A,B) :- rdf(A,owl:equivalentClass,B).
  240%owl_equivalent_class_asserted(A,B) :- rdf(B,owl:equivalentClass,A).
 owl_equivalent_class_asserted_symm(?A, ?B) is nondet
inferred equivalent class between A and B, exploiting symmetry
  247owl_equivalent_class_asserted_symm(A,B) :-
  248        (   rdf(A,owl:equivalentClass,B)
  249        ;    rdf(B,owl:equivalentClass,A)).
 owl_equivalent_property_asserted_symm(?A, ?B) is nondet
inferred equivalent property between A and B, exploiting symmetry
  255owl_equivalent_property_asserted_symm(A,B) :-
  256        (   rdf(A,owl:equivalentProperty,B)
  257        ;    rdf(B,owl:equivalentProperty,A)).
 subclass_cycle(?A) is nondet
true if there is a path between A and A following one or more subClassOf links
  266subclass_cycle(A) :- rdf_path(A,oneOrMore(rdfs:subClassOf),A).
 bnode_signature(?N, ?X) is nondet
true if X is in the signature of the construct defined by blank node N
  273bnode_signature(N,X) :-
  274        rdf(N,_,X),
  275        \+ rdf_is_bnode(X).
  276bnode_signature(N,X) :-
  277        rdf(N,_,Y),
  278        rdf_is_bnode(Y),
  279        bnode_signature(Y,X).
  280
  281
  282
  283    
  284%! owl_some(?Restr, ?Property, ?Obj) is nondet.
  285%
  286% true if Restr is a blank node representing OWL expression SomeValuesFrom(Property,Obj)
  287:- rdf_meta owl_some(r,r,r).
  288owl_some(R,P,O) :-
  289        owl:onProperty(R,P),
  290        owl:someValuesFrom(R,O).
  291
  292%! subclass_of_some(?Cls, ?Property, ?Obj) is nondet.
  293%
  294% true if Cls is a subclass of the expression SomeValuesFrom(Property,Obj)
  295:- rdf_meta subclass_of_some(r,r,r).
  296
  297subclass_of_some(C,P,O) :-
  298        owl:subClassOf(C,R),
  299        owl_some(R,P,O).
 owl_all(?Restr, ?Property, ?Obj) is nondet
true if Restr is an OWL expression AllValuesFrom(Property,Obj)
  305owl_all(R,P,O) :-
  306        owl:onProperty(R,P),
  307        owl:allValuesFrom(R,O).
  308
  309owl_restriction(R, some(P,O)) :-
  310        owl:onProperty(R,P),
  311        owl:someValuesFrom(R,O).
  312
  313owl_restriction(R, all(P,O)) :-
  314        owl:onProperty(R,P),
  315        owl:someValuesFrom(R,O).
 owl_node_info(+S, ?P, ?O, ?E) is nondet
find asserted or inferred triples for S
  322owl_node_info(S,P,O,E) :-
  323        rdf(S,P,O),
  324        bind(S,E).
  325
  326owl_node_info(S,P,O,Equiv) :-
  327        owl_equivalent_class(S,Equiv),
  328        rdf(Equiv,P,O),
  329        \+ is_blank(O).
  330owl_node_info(S,P,O,Equiv) :-
  331        owl_equivalent_class(S,Equiv),
  332        subclass_of_some(Equiv,P,O).
 class_genus(?C, ?G) is nondet
true if C EquivalentTo .... and .... and G and ...
  339class_genus(C,G) :-
  340        eq_intersection_member(C,G),
  341        \+ rdf_is_bnode(G).
 class_differentia(?C, ?P, ?Y) is nondet
true if C EquivalentTo .... and .... and (P some Y) and ...
  347class_differentia(C,P,Y) :-
  348        eq_intersection_member(C,R),
  349        owl_some(R,P,Y).
 eq_intersection_member(?C, ?M) is nondet
true if C EquivalentTo .... and .... and M and ...
  356eq_intersection_member(C,M) :-
  357        rdf(C,owl:equivalentClass,E),
  358        intersection_member(E,M).
 intersection_member(?I, ?M) is nondet
true if I is a blank node representing an intersection, and M is a member of the list
  364intersection_member(I,M) :-
  365        rdf(I,owl:intersectionOf,L),
  366        rdflist_member(L,M).
 rdflist_member(?L, ?M) is nondet
see also rdfs_member/2

this is an alternate implementation that makes the expansion to an rdf list explicit

  374rdflist_member(L,M) :-
  375        rdf_path(L,(zeroOrMore(rdf:rest)/(rdf:first)),M).
  376
  377
  378inferred_type(I,T) :-
  379        rdf_path(I,((rdf:type)/zeroOrMore(rdfs:subClassOf)),T).
 common_ancestor(?X, ?Y, ?A) is nondet
MAY MOVE TO ANOTHER MODULE
  388common_ancestor(X,Y,A) :-
  389        rdfs_subclass_of(X,A),
  390        rdfs_subclass_of(Y,A),
  391        X\=Y.
 mrca(?X, ?Y, ?A) is nondet
most recent common ancestor

MAY MOVE TO ANOTHER MODULE

  399mrca(X,Y,A) :-
  400        common_ancestor(X,Y,A),
  401        \+ ((common_ancestor(X,Y,A2),
  402             rdf_path(A2,oneOrMore(rdfs:subClassOf),A))).
  403
  404% NOTE: some of these may move to a utility library
 common_descendant(?X, ?Y, ?D) is nondet
MAY MOVE TO ANOTHER MODULE
  410common_descendant(X,Y,D) :-
  411        rdfs_subclass_of(D,X),
  412        rdfs_subclass_of(D,Y),
  413        X\=Y.
 mrcd(?X, ?Y, ?D) is nondet
MAY MOVE TO ANOTHER MODULE
  420mrcd(X,Y,D) :-
  421        common_descendant(X,Y,D),
  422        \+ ((common_descendant(X,Y,D2),
  423             rdf_path(D,oneOrMore(rdfs:subClassOf),D2))).
 egraph_common_ancestor(?X, ?Y, ?A) is nondet
version of common_ancestor/3 for graphs that have entailments materialized (egraphs)

MAY MOVE TO ANOTHER MODULE

  432egraph_common_ancestor(X,Y,A) :-
  433        subClassOf(X,A),
  434        subClassOf(Y,A),
  435        X\=Y.
 egraph_mrca(?X, ?Y, ?A) is nondet
version of mrca/3 for graphs that have entailments materialized (egraphs)

MAY MOVE TO ANOTHER MODULE

  445egraph_mrca(X,Y,A) :-
  446        egraph_common_ancestor(X,Y,A),
  447        \+ ((egraph_common_ancestor(X,Y,A2),
  448             A2\=A,
  449             subClassOf(A2,A))).
  450
  451
  452:- rdf_meta owl_edge(r,r,r,o).
  453:- rdf_meta owl_edge(r,r,r).
 owl_edge(?S, ?P, ?O, ?G) is nondet
 owl_edge(?S, ?P, ?O) is nondet
An edge in an existential graph

Either: S SubClassOf O Or: S SubClassOf P some O Or: S EquivalentTo O Or: S type O

  464owl_edge(S,P,O) :-
  465        owl_edge(S,P,O,_).
  466
  467
  468owl_edge(S,P,O,G) :-
  469        % S sub (P some O)
  470        rdf(S,rdfs:subClassOf,R,G),
  471        owl_some(R,P,O),
  472        \+ rdf_is_bnode(O),
  473        \+ rdf_is_bnode(S).
  474owl_edge(S,rdfs:subClassOf,O,G) :-
  475        % S sub O
  476        rdf(S,rdfs:subClassOf,O,G),
  477        \+ rdf_is_bnode(O),
  478        \+ rdf_is_bnode(S).
  479owl_edge(S,owl:equivalentClass,O,G) :-
  480        % S = O
  481        rdf(S,owl:equivalentClass,O,G),
  482        \+ rdf_is_bnode(O),
  483        \+ rdf_is_bnode(S).
  484owl_edge(O,owl:equivalentClass,S,G) :-
  485        % O = S (symmetric form)
  486        rdf(S,owl:equivalentClass,O,G),
  487        \+ rdf_is_bnode(O),
  488        \+ rdf_is_bnode(S).
  489owl_edge(S,P,O,G) :-
  490        % triple / object property assertion
  491        rdf(S,P,O,G),
  492        rdf_is_iri(O),
  493        rdf(S,rdf:type,owl:'NamedIndividual'),
  494        rdf(O,rdf:type,owl:'NamedIndividual').
  495todo___owl_edge(S,rdf:type,O,G) :-
  496        rdf(S,rdf:type,O,G),
  497        rdf_is_iri(O),
  498        rdf(S,rdf:type,owl:'NamedIndividual'),
  499        \+ rdf_global_id(owl:_,O).
  500
  501
  502owl_edge_query(Preds,S,^(P),O,G) :-
  503        nonvar(Preds),
  504        member(^(P),Preds),
  505        % inverse
  506        owl_edge(O,P,S,G).
  507owl_edge_query(Preds,S,P,O,G) :-
  508        owl_edge(S,P,O,G),
  509        opt_member(P,Preds).
  510
  511
  512inferred_named_individual(I,G) :-
  513        rdf(I,rdf:type,C,G),
  514        rdf_is_iri(C),
  515        \+ rdf_global_id(owl:_,C),
  516        \+ rdf_global_id(rdfs:_,C).
  517
  518assert_named_individuals :-
  519        inferred_named_individual(I,G),
  520        rdf_assert(I,rdf:type,owl:'NamedIndividual',G),
  521        debug(owl,'NI: ~w ~w',[I,G]),
  522        fail.
  523assert_named_individuals.
  524
  525assert_named_individuals_forall :-
  526        rdf_node_graph(I,G),
  527        rdf_assert(I,rdf:type,owl:'NamedIndividual',G),
  528        debug(owl,'NI: ~w ~w',[I,G]),
  529        fail.
  530assert_named_individuals_forall.
  531
  532rdf_node_graph(I,G) :- rdf(I,_,_,G).
  533rdf_node_graph(I,G) :- rdf(_,_,I,G), rdf_is_iri(I), \+ rdf_global_id(owl:'NamedIndividual',I).
 node_ancestor_graph_edge(?Node, ?S, ?P, ?O, ?G) is nondet
true if S is a reflexive superclass ancestor of Node, and SPO is a triple in G
  540node_ancestor_graph_edge(Node,S,P,O,G) :-
  541        rdfs_subclass_of(Node,S),
  542        rdf(S,P,O,G).
 owl_subgraph(+Nodes:list, +Preds:list, ?Quads:list, +Opts:list) is det
traverses owl edge graph starting from a predefined set of nodes
  548owl_subgraph(Nodes,Preds,Quads,Opts) :-
  549        owl_subgraph(Nodes,Preds,[],Quads,[],Opts).
 owl_subgraph(+Nodes:list, +Preds:list, +Quads:list, ?FinalQuads:list, +Visited:list, +Opts:list) is det
  552owl_subgraph([],_,Quads,NQuads,_,_) :-
  553        maplist(normalize_quad,Quads,NQuads).
  554owl_subgraph([Node|Nodes],Preds,Quads,FinalQuads,Visited,Opts) :-
  555        \+ member(Node,Visited),
  556        debug(owl_graph,'Query node: ~w; PredQ=~w',[Node,Preds]),
  557        setof(rdf(Node,P,O,G),(owl_edge_query(Preds,Node,P,O,G)),NewQuads),
  558        debug(owl_graph,'  Quads: ~w',[NewQuads]),
  559        !,
  560        setof(O,S^P^G^member(rdf(S,P,O,G),NewQuads),NewNodes),
  561        ord_union(Quads,NewQuads,AccQuads),
  562        append(Nodes,NewNodes,NextNodes),
  563        owl_subgraph(NextNodes,Preds,AccQuads,FinalQuads,[Node|Visited],Opts).
  564owl_subgraph([Root|Nodes],Preds,Quads,FinalQuads,Visited,Opts) :-
  565        owl_subgraph(Nodes,Preds,[root(Root)|Quads],FinalQuads,Visited,Opts).
  566
  567normalize_quad(rdf(S,^(P),O,G),rdf(O,P,S,G)) :- !.
  568normalize_quad(X,X).
  569
  570owl_edge_ancestor(S,A) :-
  571        owl_edge_ancestor(S,A,_).
  572owl_edge_ancestor(S,A,Preds) :-
  573        rdf_subject(S),
  574        owl_subgraph([S],Preds,QL,[]),
  575        member(rdf(_,_,A,_),QL).
 extract_subontology(?Objs, ?G, ?Opts) is nondet
  583extract_subontology(Objs, G, Opts) :-
  584        findall(T,(member(Obj,Objs),owl_object_triple(Obj,T,Objs,Opts)),Ts),
  585        forall(member(rdf(S,P,O),Ts),
  586               rdf_assert(S,P,O,G)).
  587
  588owl_object_triple(Obj,T,_Objs,_Opts) :-
  589        T=rdf(Obj,rdf:type,_),
  590        T.
  591owl_object_triple(Obj,T,Objs,_Opts) :-
  592        T=rdf(Obj,_P,O),
  593        T,
  594        (   rdf_is_iri(O)
  595        ->  member(O,Objs)
  596        ;   true).
  597
  598owl_object_triple(Obj,T,Objs,_Opts) :-
  599        T1=rdf(Obj,_,Z),
  600        T1,
  601        rdf_is_bnode(Z),
  602        \+ \+ (rdf(Z,_,O),member(O,Objs)),
  603        (   T=T1
  604        ;   T=rdf(Z,_,O),
  605            T,
  606            rdf_is_iri(O)).
  607
  608        
  609
  610opt_member(_,L) :- var(L),!.
  611opt_member(X,L) :- member(X,L).
  612
  613quads_object(Quads,E) :-
  614        member(rdf(S,P,O,_),Quads),
  615        (   E=S
  616        ;   E=P
  617        ;   E=O).
  618quads_object(Quads,N) :-
  619        member(root(N), Quads).
 quads_objects(?Quads, ?Objs) is nondet
  626quads_objects(Quads,Objs) :-
  627        setof(Obj,quads_object(Quads,Obj),Objs).
  628
  629
  630% transforms quads (triples + graph arg) to obograph JSON dict
  631% TODO: move this
 quads_dict(?Quads, ?Dict) is nondet
generates a OBO JSON object from a set of triples or quads

Quads = [rdf(S,P,O,G), ...]

  639quads_dict(Quads, Dict) :-
  640        setof(Obj,quads_object(Quads,Obj),Objs),
  641        maplist(owl_object_dict, Objs,  Nodes),
  642        findall(Q,(member(Q,Quads),Q=rdf(_,_,_,_)),RealQuads),
  643        maplist(quad_dict, RealQuads,  Edges),
  644        Dict = graph{nodes:Nodes, edges:Edges}.
  645
  646quad_dict(rdf(S,P,O,_), Dict) :-
  647        ensure_curie(S, Sx),
  648        ensure_curie(P, Px1),
  649        ensure_curie_or_atom(O, Ox),
  650        (   Px1='rdfs:subClassOf'
  651        ->  Px=is_a
  652        ;   Px=Px1),
  653        Dict = edge{sub:Sx, pred:Px, obj:Ox}.
  654
  655owl_object_dict(C, Dict) :-
  656        ensure_curie(C, Id),
  657        (   label(C,N1)
  658        ->  true
  659        ;   N1=C),
  660        rdf_node_type(C,Type1),
  661        upcase_atom(Type1,Type),
  662        ensure_curie_or_atom(N1, N),
  663        findall(PV, object_property_value(C,_,_,PV),PVs),
  664        findall(xref{val: Xref}, (rdf(C,'http://www.geneontology.org/formats/oboInOwl#hasDbXref',X1),ensure_atom(X1,Xref)), Xrefs),
  665        Meta = meta{ basicPropertyValues: PVs, xrefs: Xrefs },
  666        Dict = node{id:Id, type:Type, lbl:N, meta:Meta}.
  667
  668object_property_value(C,P,V,pv{pred:P,val:V}) :-
  669        rdf(C,P1,V1),
  670        ensure_curie(P1,P),
  671        rdf_is_literal(V1),
  672        literal_atom(V1,V),
  673        debug(owl,'~w PV = ~w ~q',[C,P,V]),
  674        \+ compound(V).
  675
  676literal_atom(V@_,V) :- !.
  677literal_atom(V^^_,V) :- !.
  678literal_atom(literal(type(_,V)),V) :- !.
  679literal_atom(literal(lang(_,V)),V) :- !.
  680literal_atom(literal(V),V) :- !.
  681literal_atom(V,V) :- !.
  682
  683        
  684
  685rdf_node_type(X,class) :- is_class(X),!.
  686rdf_node_type(X,property) :- is_property(X),!.
  687rdf_node_type(X,instance) :- is_instance(X),!.
  688rdf_node_type(_,unknown).
  689
  690
  691is_class(X) :- \+ \+ rdf(_,rdf:type,X).
  692is_class(X) :- rdf(X,rdf:type,owl:'Class').
  693is_property(X) :- rdf(X,rdf:type,owl:'ObjectProperty').
  694is_property(X) :- rdf(X,rdf:type,owl:'DataProperty').
  695is_property(X) :- rdf(X,rdf:type,owl:'TransitiveProperty').
  696is_property(X) :- rdf(X,rdf:type,owl:'AnnotationProperty').
  697is_property(X) :- rdf(X,rdf:type,rdfs:'Property').
  698is_property(X) :- \+ \+ rdf(_,X,_).
  699is_instance(X) :- rdf(X,rdf:type,C), \+ rdf_global_id(owl:_,C), \+ rdf_global_id(rdfs:_,C).
  700
  701
  702
  703
  704ensure_curie_or_atom(R ^^ _, R) :- !.
  705ensure_curie_or_atom(R @ _, R) :- !.
  706ensure_curie_or_atom(R, Id) :-
  707        ensure_curie(R, Id).
 ensure_curie(+Uri, ?CurieOrUriTerm) is det
translates URI to a CurieOrUriTerm
  713ensure_curie(In, Id) :-
  714        rdf_global_id(In, Uri),
  715        rdf_global_id(Id1, Uri),
  716        format(atom(Id2),'~w',[Id1]),
  717        strip_trailing_colon(Id2,Id).
  718
  719strip_trailing_colon(A,B) :-        atom_concat(B,':',A),!.
  720strip_trailing_colon(A,A).
 subsumed_prefix_namespace(?Pre, ?NS, ?Pre2, ?NS2) is nondet
  727subsumed_prefix_namespace(Pre, NS, Pre2, NS2) :-
  728        rdf_current_prefix(Pre, NS),
  729        rdf_current_prefix(Pre2, NS2),
  730        NS \= NS2,
  731        atom_concat(NS,_,NS2).
 ensure_uri(+CurieOrUriTerm, ?Uri) is det
translates CurieOrUriTerm to a URI. CurieOrUriTerm is either:
  743ensure_uri(Pre:Post, Uri) :-
  744        !,
  745        rdf_global_id(Pre:Post,Uri).
  746ensure_uri(Id, Uri) :-
  747        concat_atom([Pre,Post],:,Id),
  748        rdf_current_prefix(Pre,_),
  749        !,
  750        rdf_global_id(Pre:Post,Uri).
  751ensure_uri(X, Uri) :-
  752        rdf_global_id(X,Uri).
  753
  754
  755% TODO: move to other module
 simj_by_subclass(?C1, ?C2, ?S) is nondet
  761simj_by_subclass(C1,C2,S) :-
  762        simj_by_subclass(C1,C2,S,_,_).
 simj_by_subclass(?C1, ?C2, ?S, ?N1, ?N2) is nondet
  768simj_by_subclass(C1,C2,S,N1,N2) :-
  769        owl:class(C1),
  770        owl:class(C2),
  771        aggregate(count,X,(rdfs_subclass_of(X,C1) , rdfs_subclass_of(X,C2)),N1),
  772        aggregate(count,X,(rdfs_subclass_of(X,C1) ; rdfs_subclass_of(X,C2)),N2),
  773        N2 > 0,
  774        S is N1/N2.
  775
  776        
  777                                % === WRITING ====
 owl_assert_axiom(+Axiom, ?MainTriple, +Graph:iri) is det
 owl_assert_axiom(+Axiom, +Graph:iri) is det
 owl_assert_axiom(+Axiom) is det
asserts an axiom
  785owl_assert_axiom(Axiom) :-
  786        rdf_default_graph(G),
  787        owl_assert_axiom(Axiom,G).
  788
  789owl_assert_axiom(Axiom,G) :-
  790        owl_assert_axiom(Axiom,_,G).
  791owl_assert_axiom(equivalentTo(A,B),rdf(A,owl:equivalentClass,B),G) :-
  792        !,
  793        debug(def, 'Saving ~w = ~w to ~w',[A,B,G]),
  794        owl_assert_expression(A,Ax,G),
  795        owl_assert_expression(B,Bx,G),
  796        rdf_assert(Ax,owl:equivalentClass,Bx,G).
  797owl_assert_axiom(subClassOf(A,B),rdf(A,rdfs:subClassOf,B),G) :-
  798        !,
  799        owl_assert_expression(A,Ax,G),
  800        owl_assert_expression(B,Bx,G),
  801        rdf_assert(Ax,rdfs:subClassOf,Bx,G).
  802owl_assert_axiom(T,T,G) :-
  803        % fallback
  804        T=rdf(S,P,O),
  805        !,
  806        rdf_assert(S,P,O,G).
 owl_assert_axiom_with_anns(+Axiom, ?MainTriple, +Graph:iri, +Annotations:list) is det
 owl_assert_axiom_with_anns(+Axiom, +Graph:iri, +Annotations:list) is det
Annotations = [annotation(P1,V1), ...]
  813owl_assert_axiom_with_anns(Axiom,G,Anns) :-
  814        owl_assert_axiom_with_anns(Axiom,_,G,Anns).
  815owl_assert_axiom_with_anns(Axiom,T,G,Anns) :-
  816        owl_assert_axiom(Axiom,T,G),
  817        T=rdf(S,P,O),
  818        owl_assert_expression(P,Px,G),
  819        owl_assert_expression(S,Sx,G),
  820        owl_assert_expression(O,Ox,G),
  821        rdf_create_bnode(AxiomNode),
  822        debug(def, 'Saving AxiomAnnotation ~w = ~w -> ~w // ~w,~w,~w',[AxiomNode,AP,V,S,Px,O]),
  823        rdf_assert(AxiomNode,owl:annotatedSource,Sx,G),
  824        rdf_assert(AxiomNode,owl:annotatedProperty,Px,G),
  825        rdf_assert(AxiomNode,owl:annotatedTarget,Ox,G),
  826        rdf_assert(AxiomNode,rdf:type,owl:'Axiom',G),
  827        forall(member(annotation(AP,V),Anns),
  828               rdf_assert(AxiomNode,AP,V,G)),
  829        !.
  830owl_assert_axiom_with_anns(Axiom,T,G,Anns) :-
  831        throw(error(could_not_owl_assert(Axiom,T,G,Anns))).
  832
  833
  834
  835% TODO: axiom annotation
  836owl_assert_expression(and(Xs),Node,G) :-
  837        !,
  838        rdf_create_bnode(Node),
  839        debug(xdef,'Made IXN bnode: ~w',[Node]),
  840        rdf_assert(Node,rdf:type,owl:'Class',G),
  841        maplist({G}/[In,Out]>>owl_assert_expression(In,Out,G),Xs,IxnNodesPL),
  842        debug(xdef, 'AND list = ~w',[IxnNodesPL]),
  843        rdf_assert_list(IxnNodesPL,IxnNode,G),
  844        rdf_assert(Node,owl:intersectionOf,IxnNode,G).
  845owl_assert_expression(some(P,V),Node,G) :-
  846        !,
  847        rdf_create_bnode(Node),
  848        owl_assert_expression(P,Px,G),
  849        owl_assert_expression(V,Vx,G),
  850        rdf_assert(Node,rdf:type,owl:'Restriction',G),
  851        rdf_assert(Node,owl:onProperty,Px,G),
  852        rdf_assert(Node,owl:someValuesFrom,Vx,G).
  853owl_assert_expression(Node,Node,_) :-
  854        Node = _^^_,
  855        !.
  856owl_assert_expression(Node,Node,_) :-
  857        Node = _@_,
  858        !.
  859owl_assert_expression(P:X,Node,_) :-
  860        rdf_global_id(P:X,Node),
  861        !.
  862owl_assert_expression(Node,Node,_) :-
  863        atomic(Node),
  864        !