24:- module(prodlr, [declare_concept/1, declare_concept/2, add_to_concept/2,
   25                   declare_relation/3, add_to_relation/3,
   26                   concept_select/3, forall_select/4, atleast_select/5, atmost_select/5, self_select/3,
   27                   relation_path/3, relation_path/1, concept_name/1, concept_name_or_not/1, num/1,
   28                   concept/3,
   29                   legitimate_literal/1, thread_itemfunctor/1]).   30
   31:- assert_if_new(user:use_algebra(alg_lukasiewicz)).   32
   33:- use_module( fuzzyutils ).   34
   35:- use_module( library(lists) ).   36
   37:- dynamic concept_name/1,  concept_assert/3,  concept_sub/3, concept_sub/2.   38:- dynamic relation_name/3, relation_assert/4, relation_sub/4.   39
   40%prolog_engine(swi) :- current_prolog_flag(argv, [pl|_]).
   41%prolog_engine(yap) :- predicate_property(yap_flag(_,_), built_in).
   42
   43init_engine(swi) :-!.
   44%	assert_if_new((remove_duplicates([], []))),
   45%	assert_if_new((remove_duplicates([H|X], [H|Y]) :- delete(X, H, Z), remove_duplicates(Z,Y))).
   46
   47init_engine(yap) :-
   48	use_module( library(dialect/swi) ).
   49
   50
   51%:- prolog_engine(Engine), init_engine(Engine).
   52:- init_engine(swi).   53
   54% concept_name(?concept)
   55% predicate returns all the declared concepts.
   56concept_name(thing).
   57
   58%declare_instance(Instance) :-
   59%	atom(Instance),
   60%	assert_if_new(instance(Instance)).
   61
   62declare_concept(Concept, Super) :-
   63	atom(Concept),
   64	atom(Super),
   65	assert_if_new(concept_name(Concept)),
   66	assert_if_new(concept_sub(Concept,Super)),
   67	assert_if_new((concept_sub(Super, I, Deg) :- concept(Concept, I, Deg))).
   68
   69declare_concept(Concept) :- declare_concept(Concept, thing).
   70
   71% db_record an assertion Concept(Instance) >= Deg
   72% if there is already an assertion about Instance, we keep the one with the greater degree.
   73% i don't think that's necessary.
   74assert_instance(Concept, Instance, Deg) :-
   75	atom(Concept), atom(Instance),
   76	concept_name(Concept), is_fuzzy_degree(Deg),
   77	% instance(Instance),
   78	retractall(concept_assert(Concept, Instance, _)),
   79	asserta(concept_assert(Concept, Instance, Deg)).
   80
   81
   82% also known as: assert_many_instances_to_concept predicate
   83add_to_concept(Concept, []) :- concept_name(Concept).
   84
   85add_to_concept(Concept, [(Instance, Deg) | Rest]) :-
   86	!,
   87	assert_instance(Concept, Instance, Deg),
   88	add_to_concept(Concept, Rest),
   89	!.
   90
   91add_to_concept(Concept, [Instance | Rest]) :-
   92	add_to_concept(Concept, [(Instance, 1.0) | Rest]).
   93
   94
   95% unused because intersection of concepts can be implemented using concept_selects
   96%concept_intersect(C, C, C).
   97%concept_intersect(C1, C2, intersect(C1, C2)).
   98
   99% unused because union of concepts can be implement using multiple clauses.
  100%concept_union(C, C, C).
  101%concept_union(C1, C2, union(C1, C2)).
  102
  103% complementary will be implemented directly to concept_select.
  104concept_complement(compl(C), C) :- !.
  105concept_complement(C, compl(C)).
  106
  107% concept_degrees(#Concept, #Instance, ?Degrees).
  108concept_degrees(Concept, Instance, Degrees) :-
  109	findall(D, concept_assert(Concept, Instance, D), DegAsserted),
  110	findall(D, concept_sub(Concept, Instance, D), DegSubsumed),
  111	append(DegAsserted, DegSubsumed, Degrees).
  112
  113is_instance_of_concept(Concept, Instance) :-
  114	concept_assert(Concept, Instance, _).
  115is_instance_of_concept(Concept, Instance) :-
  116	concept_sub(Concept, Instance, _).
  117
  118% concept_degree(#Concept, #Instance, ?Deg)
  119concept_degree(Concept, Instance, Deg) :-
  120	atom(Concept), atom(Instance),
  121	(Concept = thing ->
  122		equally_fuzzy(Deg, 1.0) ;
  123		concept_degrees(Concept, Instance, Degrees),
  124		(Degrees = [] -> equally_fuzzy(Deg, 0.0) ; tnorms(disjunction, Degrees, Deg))).
  125
  126% concept(#Concept, ?Instance, ?Deg).
  127concept(Concept, Instance, Deg) :-
  128	concept_degree(Concept, Instance, Deg).
  129
  130concept(Concept, Instance, Deg) :-
  131	atom(Concept), var(Instance),
  132	is_instance_of_concept(Concept, Instance),
  133	concept_degree(Concept, Instance, Deg).
  134
  135%concept(intersect(C1, C2), I, Deg) :-
  136%	concept(C1, I, Deg1),
  137%	concept(C2, I, Deg2),
  138%	tnorm( conjunction, Deg1, Deg2, Deg ).
  139
  140%concept(union(C1, C2), I, Deg) :-
  141%	concept(C1, I, Deg1),
  142%	concept(C2, I, Deg2),
  143%	tnorm( disjunction, Deg1, Deg2, Deg ).
  144
  145concept(compl(C), I, Deg) :-
  146	concept_name(C),	% restrict infinite construction of compl(compl(compl(...)))
  147	concept(C, I, Deg1),
  148	tnorm( complement, Deg1, Deg).
  149
  150concept_name_or_not(C) :- concept_name(C).
  151concept_name_or_not(compl(C)) :- concept_name(C).
  152
  153concept_subsumed(C,C) :- !.
  154
  155concept_subsumed(C1, C2) :-
  156	concept_name_or_not(C1),
  157	concept_name_or_not(C2),
  158	findall( (I1, D1), concept(C1, I1, D1), C1List ),
  159	set_subsumed( C1List, C2 ).
  160
  161set_subsumed( [], _ ).
  162set_subsumed( [(I,D)|Rest], C) :-
  163	concept(C, I, D1), !,
  164	tnorm( implication, D, D1, Result),
  165	equally_fuzzy( Result, 1.0 ),
  166	set_subsumed( Rest, C ).
  167
  168relation_name(uni, thing, thing).
  169relation_name(Relation) :- relation_name(Relation, _, _).
  170
  171declare_relation(Relation, Domain, Range) :- declare_relation(Relation, uni, Domain, Range).
  172declare_relation(Relation, Super, Domain, Range) :-
  173	atom(Relation), atom(Super),
  174	atom(Domain), atom(Range),
  175	assert_if_new(relation_name(Relation, Domain, Range)),
  176	assert_if_new((relation_sub(Super, X, Y, Deg) :- relation(Relation, X, Y, Deg))).
  177
  178
  179assert_role(Relation, Inst1, Inst2, Deg) :-
  180	atom(Relation), atom(Inst1), atom(Inst2),
  181	%instance(Inst1), instance(Inst2),
  182	relation_name(Relation),
  183	%concept(Domain, Inst1, _),
  184	%concept(Range, Inst2, _),
  185	%!,
  186	retractall(relation_assert(Relation, Inst1, Inst2, _)),
  187	asserta(relation_assert(Relation, Inst1, Inst2, Deg)).
  188
  189% add_to_relation(+Relation, +X, +Ys)
  190add_to_relation(Relation, X, []) :- atom(Relation), atom(X).
  191add_to_relation(Relation, X, [(Y, Deg) | R]) :-
  192	assert_role(Relation, X, Y, Deg),
  193	add_to_relation(Relation, X, R).
  194
  195relation_degrees(Rel, X, Y, Degrees) :-
  196	atom(Rel), atom(X), atom(Y), 
  197	findall(D, relation_assert(Rel, X, Y, D), DegAsserted),
  198	findall(D, relation_sub(Rel, X, Y, D), DegSubsumed),
  199	append(DegAsserted, DegSubsumed, Degrees).
  200
  201relation_degree(Rel, X, Y, Deg) :-
  202	atom(Rel), atom(X), atom(Y), 
  203	(Rel = uni -> 
  204		equally_fuzzy(Deg, 1.0) ;
  205		relation_degrees(Rel, X, Y, Degrees),
  206		(Degrees = [] -> equally_fuzzy(Deg, 0.0); tnorms( disjunction, Degrees, Deg))).
  207
  208is_relation_instance(Rel, X, Y) :-
  209	relation_assert(Rel, X, Y, _).
  210is_relation_instance(Rel, X, Y) :-
  211	relation_sub(Rel, X, Y, _).
  212
  213relation(Rel, X, Y, Degree) :-
  214	relation_degree(Rel, X, Y, Degree).
  215
  216relation(Rel, X, Y, Degree) :-
  217	atom(Rel), (var(X) | var(Y)), !, 
  218	is_relation_instance(Rel, X, Y),
  219	relation_degree(Rel, X, Y, Degree).
  220
  221relation_composition([Relation], Inst1, Inst2, Deg) :-
  222	relation_name(Relation),
  223	relation(Relation, Inst1, Inst2, Deg).
  224
  225relation_composition([Rel1, Rel2 | Rest], Inst1, Inst2, Deg) :-
  226	relation_path([Rel1, Rel2 | Rest], Inst1, Inst2, _), % in case that Inst1 and/or Inst2 are not bounded
  227	%concept(thing, Inst1, _), concept(thing, Inst2, _),
  228	findall(DegOut, relation_path([Rel1, Rel2|Rest], Inst1, Inst2, DegOut), Degrees),
  229	(Degrees = [] -> equally_fuzzy(Deg, 0.0) ; sup_degree(Degrees, Deg)).
  230
  231relation_path([Rel], Inst1, Inst2, DegOut) :- relation_name(Rel), relation(Rel, Inst1, Inst2, DegOut).
  232relation_path([Rel1, Rel2 | Rest], Inst1, Inst2, DegOut):-
  233	relation_name(Rel1), relation_name(Rel2),
  234	relation(Rel1, Inst1, Y, Deg2),
  235	relation_composition([Rel2 | Rest], Y, Inst2, Deg3),
  236	tnorm( conjunction, Deg2, Deg3, DegOut ).
  237
  238
  239relation_path_arb([Rel], Domain, Range) :-
  240	relation_name(Rel, Domain, Range).
  241
  242relation_path_arb([Rel1, Rel2 |Rest], Domain, Range) :-
  243	relation_name(Rel1, Domain, _),
  244	relation_name(Rel2, Domain2, _),
  245	relation_range([Rel1], Domain2),
  246	relation_path_arb([Rel2|Rest], Domain2, Range).
  247
  248relation_path(Path, Domain, Range) :-
  249	var(Path), !,
  250	between(1, 4, N),
  251	length(Path, N),
  252	relation_path_arb(Path, Domain, Range),
  253	\+ member(uni, Path).
  254
  255relation_path(Path, Domain, Range) :-
  256	relation_path_arb(Path, Domain, Range).
  257
  258
  259relation_range(RelationPath, Range) :-
  260	relation_path(RelationPath, _, Range).
  261
  262relation_range(RelationPath, Range) :-
  263	relation_path(RelationPath, _, Range2),
  264	%concept_subsumed(Range2, Range).
  265	concept_sub(Range2, Range).
  266
  267relation_path(Path) :- relation_path(Path, _, _).
  268
  269%concept_select( ?InList, ?Concept, -OutList )
  270%
  271
  272% concept_select( +In, ?Concept, +Complement, -Out).
  273concept_select( InList, Concept, OutList ) :-
  274	concept_name_or_not(Concept),
  275	concept_select_rec(InList, Concept, OutList).
  276
  277concept_select_rec( [], _, [] ).
  278concept_select_rec( [(Instance, InDeg)|InList], Concept, [(Instance, OutDeg) | OutList] ) :-
  279	concept(Concept, Instance, Deg),
  280	tnorm( conjunction, InDeg, Deg, OutDeg1 ),
  281	(var(OutDeg) -> OutDeg = OutDeg1 ; check_less_fuzzy(OutDeg1, OutDeg)),
  282	concept_select_rec( InList, Concept, OutList ).
  290forall_select([], _, _, []).
  291forall_select([(A, D) | InList], Relation, Concept, [(A, OutDeg) | OutList]) :-
  292	relation_path(Relation),
  293	concept_name_or_not(Concept),
  294	forall(A, Relation, Concept, DegF),
  295	tnorm(conjunction, D, DegF, OutDeg1),
  296	(var(OutDeg) -> OutDeg = OutDeg1 ; check_less_fuzzy(OutDeg1, OutDeg)),
  297	forall_select(InList, Relation, Concept, OutList).
  298%forall_select(In, Relation, Concept, Out)
  299
  300forall_each(A, Relation, Concept, Deg) :-
  301	relation_composition(Relation, A, B, DegRel),
  302	concept(Concept, B, DegC),
  303	tnorm(implication, DegRel, DegC, Deg).
  304
  305forall(A, Relation, Concept, Deg) :-
  306	atom(A), !,
  307	findall(D, forall_each(A, Relation, Concept, D), Degrees),
  308	(Degrees = [] -> Deg = 0.0; inf_degree(Degrees, Deg)).
  309
  310forall(A, Relation, Concept, Deg) :-
  311	var(A), !,
  312	concept(thing, A, _),
  313	forall(A, Relation, Concept, Deg).
  314
  315
  316% every P-ary subset of Degrees are conjuncted resulting Deg.
  317% TODO: give more inspired name to predicate
  318atleast_once(Degrees, P, Deg) :-
  319	length(ParyDegrees, P),
  320	comb(Degrees, ParyDegrees),
  321	tnorms(weakconjunction, ParyDegrees, Deg).
  322
  323exists_each(A, B, Relation, Concept, Deg) :-
  324	relation_composition(Relation, A, B, DegRel),
  325	concept(Concept, B, DegC),
  326	tnorm(conjunction, DegRel, DegC, Deg).
  327
  328exists_many(A, Relation, Concept, Degrees, Many) :-
  329	atom(A), !,
  330	findall((B,D), exists_each(A, B, Relation, Concept, D), OutList),
  331	% OutSet contains only distinct role fillers
  332	remove_duplicates(OutList, OutSet),
  333	unzip(OutSet, _, Degrees1),
  334	%remove_zeros(Degrees1, Degrees),
  335	Degrees = Degrees1,
  336	length(Degrees, Many),
  337	!.
  338
  339exists_many(A, Relation, Concept, Degrees, Many) :-
  340	var(A), !,
  341	concept(thing, A, _),
  342	exists_many(A, Relation, Concept, Degrees, Many).
  343
  344% atleast_select(+InList, ?Relation, ?Concept, +Min, -OutList)
  345% ASSUMPTION: if N < Min then the Deg is 0.0
  346atleast_select([], _, _, _, []).
  347atleast_select([(A, InDeg) | Rest], Relation, Concept, Min, [(A, OutDeg) | OutList]) :-
  348	integer(Min), !,
  349	relation_path(Relation),
  350	concept_name_or_not(Concept),
  351	exists_many(A, Relation, Concept, Degrees, N),
  352	(N >= Min ->
  353		findall(Deg, (atleast_once(Degrees, Min, Deg1), tnorm(conjunction, Deg1, 1.0, Deg)), CompDegrees),
  354		sup_degree(CompDegrees, CompDeg)
  355		;
  356		equally_fuzzy(CompDeg, 0.0)
  357	),
  358	tnorm(conjunction, InDeg, CompDeg, OutDeg1),
  359	(var(OutDeg) -> OutDeg = OutDeg1 ; check_less_fuzzy(OutDeg1, OutDeg)),
  360	atleast_select(Rest, Relation, Concept, Min, OutList).
  361
  362atleast_select(InList, Relation, Concept, Min, OutList) :-
  363	var(Min), !,
  364	relation_path(Relation),
  365	concept_name_or_not(Concept),
  366	atleast_select_MaxMin(InList, Relation, Concept, MaxMin, OutList),
  367	MaxMin >= 1,
  368	between(1, MaxMin, Min),
  369	atleast_select(InList, Relation, Concept, Min, OutList).
  370
  371atleast_select_MaxMin(InList, Relation, Concept, MaxMin, OutList) :- 
  372	atleast_select_MaxMin_rec(InList, Relation, Concept, OutList, MaxMin).
  373
  374atleast_select_MaxMin_rec([(Instance, InDeg)], R, C, [(Instance, OutDeg)], Max) :-
  375	%float(InDeg), float(OutDeg), !,
  376	atleast_find_max([(Instance, InDeg)], R, C, [(Instance, OutDeg)], 1, Max).
  377
  378atleast_select_MaxMin_rec([(Instance, InDeg)|InList], Relation, Concept, [(Instance, OutDeg)|OutList], MaxMin) :-
  379	%float(InDeg), float(OutDeg), !,
  380	atleast_find_max([(Instance, InDeg)], Relation, Concept, [(Instance, OutDeg)], 1, N),
  381	atleast_select_MaxMin_rec(InList, Relation, Concept, OutList, MaxMin2),
  382	( N >= MaxMin2 -> MaxMin = MaxMin2 ; MaxMin = N ).
  383
  384atleast_find_max([(Instance, _)], Relation, Concept, [(Instance, OutDeg)], _, N) :-
  385	var(OutDeg), !,
  386	exists_many(Instance, Relation, Concept, _, N).
  387
  388atleast_find_max([(Instance,InDeg)], Relation, Concept, [(Instance, _)], K, K2) :-
  389	K2 is K + 1,
  390	atleast_select( [(Instance,InDeg)], Relation, Concept, K2, [(Instance, OutDeg2)]),
  391	equally_fuzzy(OutDeg2,0.0),
  392	!.
  393
  394atleast_find_max(InList, Relation, Concept, OutList, K, Max) :-
  395	K2 is K + 1,
  396	atleast_find_max(InList, Relation, Concept, OutList, K2, Max).
  397
  398
  399% atmost_select(+InList, ?Relation, ?Concept, +Max, -OutList) :-
  400
  401atmost_select([], _, _,_, []).
  402
  403atmost_select([(A, InDeg) | Rest], Relation, Concept, Max, [(A, OutDeg) | OutList]) :-
  404	integer(Max), !,
  405	relation_path(Relation),
  406	concept_name_or_not(Concept),
  407	exists_many(A, Relation, Concept, Degrees, N),
  408	MaxPlusOne is Max + 1,
  409	findall(Deg,
  410		(atleast_once(Degrees, MaxPlusOne, Deg1), tnorm(implication, Deg1, 0.0, Deg)),
  411		CompDegrees),
  412	inf_degree(CompDegrees, CompDeg),
  413	tnorm(conjunction, InDeg, CompDeg, OutDeg1),
  414	(var(OutDeg) -> OutDeg = OutDeg1 ; check_less_fuzzy(OutDeg1, OutDeg)),
  415	atmost_select(Rest, Relation, Concept, Max, OutList).
  416
  417atmost_select(InList, Relation, Concept, Max, OutList) :-
  418	var(Max), !,
  419	relation_path(Relation),
  420	concept_name_or_not(Concept),
  421	atmost_select_MaxMin(InList, Relation, Concept, MaxMin, OutList),
  422	MaxMin >= 0,
  423	between(0, MaxMin, Max),
  424	atmost_select(InList, Relation, Concept, Max, OutList).
  425
  426atmost_select_MaxMin(InList, Relation, Concept, MaxMin, OutList) :- 
  427	atmost_select_MaxMin_rec(InList, Relation, Concept, OutList, MaxMin).
  428
  429atmost_select_MaxMin_rec([(Instance, InDeg)], R, C, [(Instance, OutDeg)], Max) :-
  430	%float(InDeg), float(OutDeg), !,
  431	atmost_find_max([(Instance, InDeg)], R, C, [(Instance, OutDeg)], 1, Max).
  432
  433atmost_select_MaxMin_rec([(Instance, InDeg)|InList], Relation, Concept, [(Instance, OutDeg)|OutList], MaxMin) :-
  434	%float(InDeg), float(OutDeg), !,
  435	atmost_find_max([(Instance, InDeg)], Relation, Concept, [(Instance, OutDeg)], 1, N),
  436	atmost_select_MaxMin_rec(InList, Relation, Concept, OutList, MaxMin2),
  437	( N >= MaxMin2 -> MaxMin = N ; MaxMin = MaxMin2 ).
  438
  439atmost_find_max([(Instance, _)], Relation, Concept, [(Instance, OutDeg)], _, N) :-
  440	var(OutDeg), !,
  441	exists_many(Instance, Relation, Concept, _, N).
  442
  443atmost_find_max([(Instance, InDeg)], Relation, Concept, [(Instance, _)], K, K2) :-
  444	K2 is K + 1,
  445	atmost_select( [(Instance, InDeg)], Relation, Concept, K2, [(Instance, OutDeg2)]),
  446	equally_fuzzy(InDeg, OutDeg2),
  447	!.
  448
  449atmost_find_max(InList, Relation, Concept, OutList, K, Max) :-
  450	K2 is K + 1,
  451	atmost_find_max(InList, Relation, Concept, OutList, K2, Max).
  452
  453
  454% self_select( +InList, ?RelationName, -OutList )
  455
  456self_select( InList, Rel, OutList ) :-
  457	relation_path( Rel ),
  458	self_select_rec( InList, Rel, OutList ).
  459	
  460self_select_rec( [], _, [] ).
  461
  462self_select_rec( [(Instance, InDeg)|InList], Rel, [(Instance, OutDeg) | OutList] ) :-
  463	relation_composition(Rel, Instance, Instance, Deg),
  464	tnorm( conjunction, InDeg, Deg, OutDeg1 ),
  465	(var(OutDeg) -> OutDeg = OutDeg1 ; check_less_fuzzy(OutDeg1, OutDeg)),
  466	self_select_rec( InList, Rel, OutList ).
  467
  468
  469
  470%%%
  471%%% utilities
  472%%%
  473
  474unzip([], [], []).
  475unzip([(A, B) | R], [A | RA], [B | RB]) :- unzip(R, RA, RB).
  476
  477
  478comb([], []).
  479comb([X|A], [X|B]) :- comb(A, B).
  480comb([_|A], B) :- comb(A, B).
  481
  482
  483remove_zeros([],[]).
  484remove_zeros([Degree|Rest], Rest2) :-
  485	check_equally_fuzzy(Degree, 0.0),
  486	remove_zeros(Rest, Rest2), !.
  487remove_zeros([Degree|Rest], [Degree|Rest2]):-
  488	remove_zeros(Rest, Rest2).
  489
  490num(0).
  491num(1).
  492num(2).
  493num(3).
  494num(4).
  495num(5).
  496
  497thread_itemfunctor(concept_select/3).
  498thread_itemfunctor(forall_select/4).
  499thread_itemfunctor(atleast_select/5).
  500thread_itemfunctor(atmost_select/5).
  501thread_itemfunctor(self_select/3).
  502
  503inout_lit(Term, Input, Output) :-
  504    Term =.. List,
  505    length(List, N),
  506    N >= 3,
  507    List = [ _, Input | _ ],
  508    last(List, Output).
  509
  510inout_thread(','(A, B), Input, Output) :-
  511    inout_lit(A, Input, FirstOut),
  512    inout_thread(B, FirstOut, Output), !.
  513
  514inout_thread(Atom, Input, Output) :- inout_lit(Atom, Input, Output), !.
  515
  516% has_pieces(+Body, -AtomList).
  517% returns the body as a list of atoms
  518has_pieces(true, []) :- !.
  519has_pieces(','(A, R), [A|Z]) :- has_pieces(R, Z), !.
  520has_pieces(A, [A]) :- !.
  521
  522% concat_thread(+List, -Body)
  523% concat_thread: concat a list of literals as a thread.
  524concat_thread([A], A) :- !.
  525concat_thread([A|Z], ','(A, Z1)) :- 
  526    concat_thread(Z, Z1),
  527    inout_lit(A, _, Out),
  528    inout_thread(Z1, Out, _).
  529
  530% count_literals(+Literals, -Count)
  531count_literals(Lits, Count) :- has_pieces(Lits, LitList), length(LitList, Count).
  532
  533% connect_thread(+Clause)
  534% connect_thread: Connect the head variables with the body variables.
  535connect_thread((Head:-Body)) :-
  536    inout_lit(Head, Input, Output),
  537    inout_thread(Body, Input, Output), !.
  538
  539% append_thread(+Literal, +Body, -BodyWithLit)
  540% append and connect the Literal to the Body resulting to BodyWithLit.
  541append_thread(Lit, Body, BodyWith) :-
  542    has_pieces(Body, Atoms),
  543    append(Atoms, [Lit], Atoms2),
  544    concat_thread(Atoms2, BodyWith), !.
  545
  546concept_r(C, C).
  547concept_r(C, R) :- concept_sub(C, R).
  548
  549% legitimate_literal(?Lit)
  550% legitimate_literal: generates or validates if the literal is legidimate.
  551% In other words, if the concepts and the relation path arguments are filled
  552% with a value that make sense.
  553legitimate_literal(concept_select(_,C,_)) :- concept_name_or_not(C).
  554
  555legitimate_literal(forall_select(_, R, C, _)) :- relation_path(R, _, Range), concept_r(C, Range).
  556
  557legitimate_literal(atleast_select(_, R, C, N, _)) :- num(N), relation_path(R, _, Range), concept_r(C, Range).
  558
  559legitimate_literal(atmost_select(_, R, C, N, _)) :- num(N), relation_path(R, _, Range), concept_r(C, Range).
  560
  561legitimate_literal(self_select(_, R, B)) :- relation_path(R).
  562
  563%%%
  564%%%  yadlr front-end
  565%%%
  566
  567yadlr_init( KB ) :- 
  568	retractKB( KB ).
  569
  570% TODO: check if it already exists, and fail
  571yadlr_concept( KB, ConceptName ) :-
  572	declare_concept(ConceptName),
  573	db_recordz( KB, yconcept(ConceptName), _ ).
  574
  575yadlr_relation( KB, RelationName ) :-
  576	declare_relation(RelationName, thing, thing),
  577	db_recordz( KB, yrelation(RelationName), _ ).
  578
  579yadlr_instance( KB, InstanceName ) :-
  580	db_recordz( KB, yinstance(InstanceName), _ ).
  581
  582yadlr_concept_name( KB, ConceptName ) :-
  583	db_recorded( KB, yconcept(ConceptName), _ ).
  584
  585yadlr_relation_name( KB, RelationName ) :-
  586	db_recorded( KB, yrelation(RelationName), _ ).
  587
  588yadlr_instance_name( KB, InstanceName ) :-
  589	db_recorded( KB, yinstance(InstanceName), _ ).
  590
  591yadlr_assert( KB, Formula, FuzzyDegree ) :-
  592	clausify_abstract( Formula, FuzzyDegree, Clauses ),
  593	yadlr_assert_many( KB, Clauses ).
  594
  595% place grounds facts at the top
  596/*
  597yadlr_assert_one( KB, Clause ) :-
  598	yadlr_clause_body( Clause, [] ),
  599	!,
  600	db_recorda( KB, Clause, _ ).
  601yadlr_assert_one( KB, Clause ) :-
  602	db_recordz( KB, Clause, _ ).
  603*/
  604
  605yadlr_assert_one(KB, dla(concept, Assertion, Degree)) :-
  606	is_concept(Assertion, Concept, Instance),
  607	yadlr_concept_name(KB, Concept),
  608	%yadlr_instance_name(KB, Instance),
  609	!,
  610	add_to_concept(Concept, [(Instance, Degree)]).
  611
  612yadlr_assert_one(KB, dla(relation, Assertion, Degree)) :-
  613	is_relation(Assertion, Relation, X, Y),
  614	yadlr_relation_name(KB, Relation),
  615	%yadlr_instance_name(KB, X),
  616	%yadlr_instance_name(KB, Y),
  617	!,
  618	add_to_relation(Relation, X, [(Y, Degree)]).
  619
  620yadlr_assert_one(_, DLClause) :-
  621	mkplclause(DLClause, Clause),
  622	assert_if_new(Clause),
  623	!.
  624
  625yadlr_assert_many( _, []).
  626yadlr_assert_many( KB, [Head|Rest] ) :-
  627	yadlr_assert_one(KB, Head),
  628	yadlr_assert_many(KB, Rest).
  629
  630retractKB( KB ) :-
  631	prolog_engine(swi),
  632	db_recorded( KB, _, Ref ),
  633	erase( Ref ),
  634	fail.
  635retractKB( _ ) :-
  636	prolog_engine(swi),
  637	!.
  638%retractKB( KB ) :-
  639%	eraseall( KB ).
  640
  641yadlr_retrieve_concept( KB, ConceptName ) :-
  642	db_recorded( KB, yconcept(ConceptName), _ ).
  643
  644yadlr_retrieve_relation( KB, RelationName ) :-
  645	db_recorded( KB, yrelation(RelationName), _ ).
  646
  647yadlr_retrieve_instance( KB, InstanceName ) :-
  648	db_recorded( KB, yinstance(InstanceName), _ ).
  649
  650% try to transform some not so arbitrary formula into acceptable horn clauses.
  651
  652clausify_abstract(Formula, FuzzyDegree, Clauses ) :-
  653	clausify_concept(Formula, FuzzyDegree, Clauses).
  654
  655clausify_abstract(Formula, FuzzyDegree, Clauses ) :-
  656	clausify_role(Formula, FuzzyDegree, Clauses).
  657
  658clausify_abstract(Formula, FuzzyDegree, Clauses ) :-
  659	clausify_assertion(Formula, FuzzyDegree, Clauses).
  660
  661clausify_concept(all(X, dlimplies(Body, Head)), FuzzyDegree, Clauses) :-
  662	is_concept(Head, H, X),
  663	norm_concept(X, Body, DLBody),
  664	dlclausify(concept, (H :- DLBody), FuzzyDegree, Clauses).
  665
  666clausify_concept(all(X, dlequiv(B1, B2)), FuzzyDegree, Clauses) :-
  667	is_concept(B2, _, _) ->
  668		clausify_concept(all(X, dlimplies(B1, B2)), FuzzyDegree, Clauses);
  669		clausify_concept(all(X, dlimplies(B2, B1)), FuzzyDegree, Clauses).
  670
  671clausify_role(all(X, all(Y, dlimplies(Body, Head))), FuzzyDegree, Clauses) :-
  672	is_relation(Head, R, X, Y),
  673	norm_relation(X, Y, Body, DLBody),
  674	dlclausify(relation, (R :- DLBody), FuzzyDegree, Clauses).
  675
  676clausify_assertion(Fmt, FuzzyDegree, [dla(concept, Fmt, FuzzyDegree)]) :-
  677	is_concept(Fmt, C, X),
  678	atom(C), atom(X), !.
  679
  680clausify_assertion(Fmt, FuzzyDegree, [dla(relation, Fmt, FuzzyDegree)]) :-
  681	is_relation(Fmt, R, X, Y),
  682	atom(R), atom(X), atom(Y),
  683	!.
  684
  685dlclausify(T, (H :- DLBody), Degree, Clauses) :-
  686	dlnnf(DLBody, NNF),
  687	dldnf(NNF, DNF),
  688	dlor_to_list(DNF, ListOfBodies),
  689	dlclausify_attach(T, H, ListOfBodies, Degree, Clauses).
  690
  691%dlclausify_attach(H, [],    Deg, [dlc(H,[],Deg)]).
  692dlclausify_attach(T, H, [B],   Deg, [dlc(T, H, B, Deg)]).
  693dlclausify_attach(T, H, [B|R], Deg, [dlc(T, H, B, Deg)|R0]) :- dlclausify_attach(T, H, R, Deg, R0).
  694
  695
  696dlor_to_list(dlor(A, B), List)  :- !,
  697	dlor_to_list(A, LA),
  698	dlor_to_list(B, LB),
  699	append(LA, LB, List).
  700dlor_to_list(X, [X]).
  701
  702is_concept(Fmt, C, X) :-
  703	functor(Fmt, C, 1),
  704	arg(1, Fmt, X).
  705
  706is_relation(R, Relation, X, Y) :- !,
  707	functor(R, Relation, 2),
  708	arg(1, R, X),
  709	arg(2, R, Y).
  710
  711%makes a prolog clause that can be asserted
  712mkplclause(dlc(concept, Head, Body, _), (PlHead:-PlBody)) :-
  713	mkplhead(Head, (I,D), PlHead),
  714	mkplbody(Body, [(I,1.0)], [(I,D)], PlBody).
  715
  716mkplhead(Head, (I,D), concept_sub(Head,I,D)).
  717mkplbody(dland(A, B), Input, Output, ','(P,Q)) :-
  718	mkplbody(A, Input, Pipe, P),
  719	mkplbody(B, Pipe,  Output, Q).
  720mkplbody(dlconcept(C),      I, O, concept_select(I, C0, O))        :- mkplconcept(dlconcept(C), C0).
  721mkplbody(dlnot(C),          I, O, concept_select(I, C0, O))        :- mkplconcept(dlnot(C), C0).
  722mkplbody(forall(Rp, C),     I, O, forall_select(I, Rp, C0, O))     :- mkplconcept(C, C0).
  723mkplbody(exists(Rp, C),     I, O, atleast_select(I, Rp, C0, 1, O)) :- mkplconcept(C, C0).
  724mkplbody(atleast(N, Rp, C), I, O, atleast_select(I, Rp, C0, N, O)) :- mkplconcept(C, C0).
  725mkplbody(atmost(N, Rp, C),  I, O, atmost_select(I, Rp, C0, N, O))  :- mkplconcept(C, C0).
  726
  727mkplconcept(dlconcept(C), C).
  728mkplconcept(dlnot(dlconcept(C)), compl(C)).
  729
  730
  731% norm(+Formula, -NormFormula)
  732% Normalize the formula into a more managable form
  733% Syntax:
  734% NC = dlforall([R1, R2, ...], C)
  735%    | dlexists([R1, ...], C)
  736%    | dlatleast([R1, ..], N, C)
  737%    | dlatmost([R1, ..], N, C)
  738%    | dlcompl(C)
  739%    | C
  740%  C = dlconcept(NC)
  741%  NC1 = NC and NC1
  742%  NC2 = NC1 or NC2
  743
  744
  745%normalization of concept and relations
  746 
  747norm_concept(X, all(Y, dlimplies(R, F)), all(Rel, NC)) :- !,
  748	is_relation(R, Rel, X, Y),
  749	norm_concept(Y, F, NC),
  750	(Nrm = all(R1, NC1) -> Rel = [R0|R1], NC = NC1 ;
  751                               Rel = [R0], NC = Nrm).
  752
  753norm_concept(X, exists(Y, dland(R, F)), exists(Rel, NC)) :- !,
  754	is_relation(R, R0, X, Y),
  755	norm_concept(Y, F, Nrm),
  756	(Nrm = exists(R1, NC1) -> Rel = [R0|R1], NC = NC1 ;
  757                                  Rel = [R0], NC = Nrm).
  758
  759norm_concept(X, exists(Y, Fmt), atleast(N, [Relation], Concept)) :- !,
  760	collectexists(exists(Y, Fmt), [], Fmt1, Vars),
  761	length(Vars, N),
  762	groupN(X, Vars, Fmt1, dland(R, C)),
  763	is_relation(R, Relation, X, Y),
  764	norm_concept(Y, C, Concept).
  765
  766norm_concept(X, dlnot(Fmt), dlnot(Fmt1)) :- norm_concept(X, Fmt, Fmt1).
  767
  768norm_concept(X, Fmt, dlconcept(C)) :- is_concept(Fmt, C, X).
  769
  770norm_concept(X, dland(F, G), dland(F0, G0)) :-
  771	norm_concept(X, F, F0), norm_concept(X, G, G0).
  772
  773norm_concept(X, dlor(F, G), dlor(F0, G0)) :-
  774	norm_concept(X, F, F0), norm_concept(X, G, G0).
  775
  776
  777norm_relation(X, Y, dlor(F, G), dlor(F0, G0)) :- !,
  778	norm_relation(X, Y, F, F0),
  779	norm_relatin(X, Y, G, G0).
  780
  781norm_relation(X, Y, dland(F, G), dland(F0, G0)) :- !,
  782	norm_relation(X, Y, F, F0),
  783	norm_relation(X, Y, G, G0).
  784
  785norm_relation(X, Y, R, dlrel(Relname)) :- !,
  786	is_relation(R, Relname, X, Y).
  787
  788
  789%utilities for normalizing the rules
  790
  791% some nasty grouping
  792groupN(_, [_], Fmt, Fmt) :- !.
  793groupN(X, Vars, Fmt, FmtGrp) :- groupN_rec(X, [], Vars, Fmt, _, FmtGrp).
  794
  795groupN_rec(_, V, [], dlalldifferent(V), FmtGrp, FmtGrp).
  796
  797groupN_rec(_, _, [_], Fmt, Fmt, Fmt).
  798
  799groupN_rec(X, [], V, dland(Fmt, dlalldifferent(V)), FmtGrp, FmtGrp) :- !,
  800	groupN_rec(X, [], V, Fmt, _, FmtGrp).
  801
  802groupN_rec(X, V, [Y|R], dland(Fmt, RFmt), FmtGrp, FmtGrp) :-
  803	groupN_rec(X, [Y|V], R, RFmt, Fmt, FmtGrp).
  804
  805
  806collectexists(exists(Y, Formula), VarsSoFar, FormulaWithoutExists, Vars) :-
  807	!, collectexists(Formula, [Y|VarsSoFar], FormulaWithoutExists, Vars).
  808collectexists(Formula, Vars, Formula, Vars).
  809
  810
  811% my variant of negation normal form implementation for description logics
  812
  813dlnnf(X, Y) :- dlnnf(X, _, Y, _).
  814
  815dlnnf(all(X,F),FreeV,all(X,NNF),Paths) :- !,
  816	dlnnf(F,[X|FreeV],NNF,Paths).
  817
  818dlnnf(exists(X,Fml),FreeV,exists(X,NNF),Paths) :- !,
  819	dlnnf(Fml,[X|FreeV],NNF,Paths).
  820
  821dlnnf(atleast(N, X,Fml),FreeV,atleast(N,X,NNF),Paths) :- !,
  822	dlnnf(Fml,[X|FreeV],NNF,Paths).
  823
  824dlnnf(atmost(N, X,Fml),FreeV,atmost(N,X,NNF),Paths) :- !,
  825	dlnnf(Fml,[X|FreeV],NNF,Paths).
  826
  827dlnnf(dland(A,B),FreeV,NNF,Paths) :- !,
  828	dlnnf(A,FreeV,NNF1,Paths1),
  829	dlnnf(B,FreeV,NNF2,Paths2),
  830	Paths is Paths1 * Paths2,
  831	(Paths1 > Paths2 -> NNF = dland(NNF2,NNF1);
  832		            NNF = dland(NNF1,NNF2)).
  833
  834dlnnf(dlor(A,B),FreeV,NNF,Paths) :- !,
  835	dlnnf(A,FreeV,NNF1,Paths1),
  836	dlnnf(B,FreeV,NNF2,Paths2),
  837	Paths is Paths1 + Paths2,
  838	(Paths1 > Paths2 -> NNF = dlor(NNF2,NNF1);
  839		            NNF = dlor(NNF1,NNF2)).
  840
  841dlnnf(Fml,FreeV,NNF,Paths) :- 
  842	(Fml = dlnot(dlnot(A))       -> Fml1 = A;
  843	 Fml = dlnot(all(X,F))       -> Fml1 = exists(X,dlnot(F));
  844	 Fml = dlnot(exists(X,F))    -> Fml1 = all(X,dlnot(F));
  845	 Fml = dlnot(atleast(N,X,F)) -> N1 is N - 1, Fml1 = atmost(N1,X,F);
  846	 Fml = dlnot(atmost(N,X,F))  -> N1 is N + 1, Fml1 = atleast(N1,X,F);
  847	 Fml = dlnot(dlor(A,B))      -> Fml1 = dland( dlnot(A), dlnot(B) );
  848	 Fml = dlnot(dland(A,B))     -> Fml1 = dlor( dlnot(A), dlnot(B) );
  849	 Fml = dlimplies(A,B)        -> Fml1 = dlor( dlnot(A), B );
  850	 Fml = dlnot(dlimplies(A,B)) -> Fml1 = dland( A, dlnot(B) );
  851	 Fml = dlequiv(A,B)          -> Fml1 = dlor( dland(A, B), dland(dlnot(A), dlnot(B)) );
  852	 Fml = dlnot(dlequiv(A,B))   -> Fml1 = dlor( dland(A, dlnot(B)) , dland(dlnot(A), B) )
  853	),!,
  854	dlnnf(Fml1,FreeV,NNF,Paths).
  855
  856dlnnf(Lit,_,Lit,1).
  857
  858
  859% my variant of disjunctive normal form implementation for description logics
  860dldnf(A, B) :- dnf(A, B).
  861
  862dnf( dlor(P,Q),  dlor(P1,Q1) ) :- !, dnf(P, P1), dnf(Q, Q1).
  863dnf( dland(P,Q), DNF) :- !, dnf(P, P1), dnf(Q, Q1), dnf1( dland(P1,Q1), DNF).
  864dnf(DNF,       DNF).
  865
  866dnf1( dland(P, dlor(Q,R)),  dlor(P1,Q1) ):- !, dnf1( dland(P,Q), P1), dnf1( dland(P,R), Q1).
  867dnf1( dland( dlor(P,Q), R), dlor(P1,Q1) ):- !, dnf1( dland(P,R), P1), dnf1( dland(Q,R), Q1).
  868dnf1( DNF,                  DNF ).
  869
  870%%% not prenex form (actually the opposite of prenex form. Push quantifiers inside conjunctions and disjunctions)
  871% npf(+Fmt ?NPF)
  872
  873dlnpf(all(X, dland(A, B)), dland(all(X,A0), all(X,B0))) :- !, 
  874	dlnpf(A, A0), dlnpf(B, B0).
  875
  876dlnpf(all(X, dlor(A, B)), dlor(all(X,A0), all(X,B0))) :- !,
  877	dlnpf(A, A0), dlnpf(B, B0).
  878
  879dlnpf(exists(X, dland(A, B)), dland(exists(X, A0), exists(X, B0))) :- !, 
  880	dlnpf(A, A0), dlnpf(B, B0).
  881
  882dlnpf(exists(X, dlor(A, B)), dlor(exists(X, A0), exists(X, B0))) :- !,
  883	dlnpf(A, A0), dlnpf(B, B0).
  884
  885dlnpf(NPF, NPF)