1% This file is part of the Attempto Parsing Engine (APE).
    2% Copyright 2008-2010, Kaarel Kaljurand <kaljurand@gmail.com>.
    3%
    4% The Attempto Parsing Engine (APE) is free software: you can redistribute it and/or modify it
    5% under the terms of the GNU Lesser General Public License as published by the Free Software
    6% Foundation, either version 3 of the License, or (at your option) any later version.
    7%
    8% The Attempto Parsing Engine (APE) is distributed in the hope that it will be useful, but WITHOUT
    9% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
   10% PURPOSE. See the GNU Lesser General Public License for more details.
   11%
   12% You should have received a copy of the GNU Lesser General Public License along with the Attempto
   13% Parsing Engine (APE). If not, see http://www.gnu.org/licenses/.
   14
   15
   16:- module(implication_to_swrl, [
   17		implication_to_swrl/3
   18	]).   19
   20:- use_module(drs_to_owlswrl_core, [
   21		is_toplevel/3,
   22		get_entity/3,
   23		condlist_and/4,
   24		is_object_with_generalized_quantifier/1,
   25		has_dom_for_member/3,
   26		dataitem_datavalue_datatypeuri/3
   27	]).

DRS implication to SWRL-rule translator

Translate an Attempto DRS implication into Semantic Web Rule Language (SWRL) rule.

We use the SWRL rule syntax specified in http://www.webont.org/owled/2009/papers/owled2009_submission_16.pdf

TODO: add a constraint that the variables in the head is a subset of the variables in the body.

author
- Kaarel Kaljurand
version
- 2010-12-14 */
 implication_to_swrl(+Condition:term, +RefList:list, -Implies:term) is semidet
Arguments:
Condition- is a DRS implication condition
RefList- is a list of DRS toplevel referents
Implies- is a SWRL 'DLSafeRule'-rule
   51implication_to_swrl(
   52	'=>'(CondList1, CondList2),
   53	RefList,
   54	'DLSafeRule'('Body'(AtomList1), 'Head'(AtomList2))
   55) :-
   56	condlist_atomlist(CondList1, RefList, AtomList1),
   57	condlist_atomlist(CondList2, RefList, AtomList2).
 condlist_atomlist(+ConditionList:list, +RefList:list, -AtomList:list) is det
Note that most conditions can produce several SWRL atoms because an argument of the condition can be a complex expression which will have to be unravelled into multiple SWRL builtins.
Arguments:
ConditionList- is a list of DRS conditions
RefList- is a list of DRS toplevel referents
AtomList- is list of SWRL atoms
   70condlist_atomlist([], _, []).
   71
   72% Attempt to roll up the whole condition list into a class expression
   73% E.g.: If X loves Y and Y loves X then X is a man.
   74% We need an additional contraint that it exposes all the variables
   75% that are also present in the body.
   76%condlist_atomlist(CondList, RefList, ['ClassAtom'(Class, OutX)]) :-
   77%	condlist_and(X, CondList, RefList, Class),
   78%	get_argument(X, RefList, object, OutX, _).
   79
   80% BUG: Experimental
   81% Ignore 'something', 'thing', 'X', etc.
   82% The idea is that otherwise they would be typed as owl:Thing,
   83% i.e. as objects, but maybe the DRS uses them in data expressions.
   84% So we don't want to make the object vs data distinction yet.
   85% Test: If X = 1 + 2 then X = 3.
   86% Test: If there is X and there is Y then X knows Y.
   87% Test: For everything John likes Mary.
   88% Since some conditions are ignored it might happen that the
   89% head or the body becomes empty, but this is OK I guess.
   90condlist_atomlist([Condition | ConditionList], RefList, AtomList) :-
   91	has_dom_for_member(_Ref, [Condition], []),
   92	!,
   93	condlist_atomlist(ConditionList, RefList, AtomList).
   94
   95condlist_atomlist([Condition | ConditionList], RefList, AtomList) :-
   96	condition_atomlist(Condition, RefList, AtomList1),
   97	condlist_atomlist(ConditionList, RefList, AtomList2),
   98	append(AtomList1, AtomList2, AtomList).
   99
  100
  101/*
  102% BUG: experimental
  103% BUG: Add a restriction that all variables used in predicate-conditions
  104% must be declared in object-conditions.
  105
  106condlist_atomlist([], _RefList, []).
  107
  108condlist_atomlist([Condition | CondList], RefList, [Atom | AtomList]) :-
  109	(
  110		Condition = object(D, Value, countable,  na, _, _)-_
  111	->
  112		get_entity(class, Value, NamedClass),
  113		select(Condition1, CondList, CondList1),
  114		condlist_class(D, Condition1, CondList1, RefList, AndClass, CondList2),
  115		Atom = 'description'(and(NamedClass, AndClass), 'I-variable'(D))
  116	;
  117		condition_atom(Condition, RefList, Atom),
  118		CondList2 = CondList
  119	),
  120	condlist_atomlist(CondList2, RefList, AtomList).
  121*/
 condition_atomlist(+Condition:term, -Atoms:list) is det
Arguments:
Condition- is a DRS condition
RefList- is a list of DRS toplevel referents
Atoms- is a list of SWRL atoms
  132% We allow no generalized quantifiers
  133condition_atomlist(Condition, _, _) :-
  134	is_object_with_generalized_quantifier(Condition),
  135	!,
  136	fail.
  137
  138condition_atomlist(formula(Expr1, Comp, Expr2)-_, RefList, Builtins) :-
  139	expr_to_builtins(Expr1, Var1, B1),
  140	expr_to_builtins(Expr2, Var2, B1, B2),
  141	add_relation(Comp, Var1, Var2, RefList, B2, Builtins).
  142
  143condition_atomlist(object(X, Value, _,  na, _, _)-_, _, ['ClassAtom'(NamedClass, Variable)]) :-
  144	get_variable(X, Variable),
  145	get_entity(class, Value, NamedClass).
  146
  147condition_atomlist('-'([predicate(_, be, X1, X2)-_]), RefList, ['DifferentIndividualsAtom'(OutX1, OutX2)]) :-
  148	get_argument(X1, RefList, object, OutX1, _),
  149	get_argument(X2, RefList, object, OutX2, _).
  150
  151condition_atomlist(predicate(_, be, X1, X2)-_, RefList, ['SameIndividualAtom'(OutX1, OutX2)]) :-
  152	get_argument(X1, RefList, object, OutX1, _),
  153	get_argument(X2, RefList, object, OutX2, _).
  154
  155condition_atomlist(predicate(_, Value, X1, X2)-_, RefList, ['DataPropertyAtom'(DataProperty, OutX1, OutX2) | L]) :-
  156	Value \= be,
  157	get_entity(data_property, Value, DataProperty),
  158	get_argument(X1, RefList, object, OutX1, L1),
  159	get_argument(X2, RefList, data, OutX2, L2),
  160	append(L1, L2, L).
  161
  162condition_atomlist(predicate(_, Value, X1, X2)-_, RefList, ['ObjectPropertyAtom'(ObjectProperty, OutX1, OutX2)]) :-
  163	Value \= be,
  164	get_entity(object_property, Value, ObjectProperty),
  165	get_argument(X1, RefList, object, OutX1, _),
  166	get_argument(X2, RefList, object, OutX2, _).
  167
  168% Sublist
  169% E.g. If a man owns a car then the man likes the car and likes exactly 3 cats.
  170% E.g. If John owns a car then Mary likes a car and likes at most 3 cats.
  171condition_atomlist([C | Cs], RefList, ['ClassAtom'(SubListClass, OutX)]) :-
  172	condlist_and(X, [C | Cs], RefList, SubListClass),
  173	get_argument(X, RefList, object, OutX, _).
  174
  175% Note that X can point to an Individual (i.e. not only a variable),
  176% see e.g. "If John does not like Mary then a man does not like a woman."
  177condition_atomlist('-'(Not), RefList, ['ClassAtom'('ObjectComplementOf'(NotClass), OutX)]) :-
  178	condlist_and(X, Not, RefList, NotClass),
  179	get_argument(X, RefList, object, OutX, _).
  180
  181% Note that X can point to an Individual.
  182condition_atomlist('v'(Or1, Or2), RefList, ['ClassAtom'('ObjectUnionOf'([Or1Class, Or2Class]), OutX)]) :-
  183	condlist_and(X, Or1, RefList, Or1Class),
  184	condlist_and(X, Or2, RefList, Or2Class),
  185	get_argument(X, RefList, object, OutX, _).
 get_argument(+X:term, +RefList:list, -Type:atom, -Argument:term, -Atoms:list) is det
Arguments:
X- is a discourse referent, expr-term, int/1, real/1, or string/1
RefList- is a list of DRS toplevel referents
Type- is the type of the argument, i.e. one of {data, object, _}
Argument- is a SWRL variable, OWL individual, or OWL data value
Atoms- is a list of SWRL atoms (empty if X produces no builtins)
  196get_argument(expr(X, Y, Z), _RefList, data, Var, Builtins) :-
  197	!,
  198	expr_to_builtins(expr(X, Y, Z), Var, Builtins).
  199
  200% int/1, real/1, string/1
  201% BUG: use a predicate that already returns the ^^/2 term
  202% to make sure that this term is used everywhere in DRS->OWL/SWRL
  203% where numbers are represented.
  204get_argument(DataItem, _RefList, data, '^^'(DataValue, DataTypeUri), []) :-
  205	dataitem_datavalue_datatypeuri(DataItem, DataValue, DataTypeUri),
  206	!.
  207
  208get_argument(X, RefList, object, Individual, []) :-
  209	is_toplevel(X, RefList, 'ObjectOneOf'([Individual])),
  210	!.
  211
  212get_argument('$VAR'(X), _RefList, object, Variable, []) :-
  213	get_variable(X, Variable).
  214
  215get_argument(X, _RefList, object, X, []).
 add_relation(+Relation:atom, +Var1, +Var2, +BIn:list, -BOut:list) is det
Arguments:
Relation- is one of {'>', '<', '='} ...
bug
- try to output less code, e.g. instead of 'equal' just unify: add_relation('=', Var, Var, B, B).
  225add_relation(Relation, Var1, Var2, RefList, B, ['BuiltInAtom'(swrlb:Builtin, [OutVar1, OutVar2]) | B]) :-
  226	relation_builtin(Relation, Builtin),
  227	get_argument(Var1, RefList, _, OutVar1, _),
  228	get_argument(Var2, RefList, _, OutVar2, _).
  229
  230
  231% expr_to_builtins(+Expr:term, -EList:list) is det.
  232% expr_to_builtins(+Expr:term, -Var:atom, -EList:list) is det.
  233%
  234% Flattens the expression (a tree) into a list simple expressions
  235% that are connected by expression handles. E.g.
  236%
  237%==
  238% ?- expr_to_builtins(expr(*, expr(+, 1, 2), 3), L).
  239% L = [builtin(multiply, G295, G297, 3), builtin(add, G297, 1, 2)].
  240%==
  241%
  242% @param Expr is a term in the form expr(Op, Expr1, Expr2)
  243% @param Var is a variable to be used as handle for the topmost expression
  244% @param Builtins is a list of SWRL built-in predicates
  245%
  246expr_to_builtins(Expr, List) :-
  247	expr_to_builtins(Expr, _, List).
  248
  249expr_to_builtins(Expr, Var, List) :-
  250	expr_to_builtins(Expr, Var, [], List).
  251
  252expr_to_builtins(expr(Op, E1, E2), Var, LIn, ['BuiltInAtom'(swrlb:Builtin, [Var, Var1, Var2]) | LOut]) :-
  253	!,
  254	op_builtin(Op, Builtin),
  255	get_swrl_variable(Var),
  256	expr_to_builtins(E1, Var1, LIn, LTmp),
  257	expr_to_builtins(E2, Var2, LTmp, LOut).
  258
  259% @bug: why is RefList here empty?
  260expr_to_builtins(Var, OutVar, List, List) :-
  261	get_argument(Var, [], _, OutVar, _).
 get_swrl_variable(-SwrlVariable:term) is det
Generate a new SWRL variable (prefixed by 'g' to avoid a possible nameclash)
bug
- It's not nice to use gensym/2
  270get_swrl_variable(Variable) :-
  271	gensym(g, GenSym),
  272	get_variable(GenSym, Variable).
 get_variable(+Var, -Variable)
  278get_variable('$VAR'(X), 'Variable'(Var)) :-
  279	!,
  280	with_output_to(atom(Var), format("urn:swrl#x~w", [X])).
  281
  282get_variable(X, 'Variable'(Var)) :-
  283	with_output_to(atom(Var), format("urn:swrl#x~w", [X])).
 relation_builtin(?Relation:atom, ?Builtin:atom) is det
SWRL built-ins for comparisons (complete coverage of the 6 built-ins)
Arguments:
Relation- is one of {'>', '<', '=', '\=', '=<', '>='}
Builtin- is SWRL built-in
  293relation_builtin('=', equal).
  294relation_builtin('\\=', notEqual).
  295relation_builtin('<', lessThan).
  296relation_builtin('=<', lessThanOrEqual).
  297relation_builtin('>', greaterThan).
  298relation_builtin('>=', greaterThanOrEqual).
 op_builtin(?Op:atom, ?Builtin:atom) is det
SWRL math built-ins and string built-ins.
Arguments:
Op- is DRS (binary) operator
Builtin- is SWRL built-in
  308op_builtin('+', add).
  309op_builtin('-', subtract).
  310op_builtin('*', multiply).
  311op_builtin('/', divide).
  312op_builtin('^', pow).
  313op_builtin('&', stringConcat)