Prolog - ASP 'not' to Prolog negate - prolog

I have an example problem in Answer Set Programming (ASP). When I try to make the equivalent code in Prolog, I keep getting stuck with the not blocked.
This is the ASP code:
road(berlin,potsdam).
road(potsdam,werder).
road(werder,brandenburg).
road(X,Y) :- road(Y,X).
blocked(werder,brandenburg).
route(X,Y) :- road(X,Y), not blocked(X,Y).
route(X,Y) :- route(X,Z), route(Z,Y).
drive(X) :- route(berlin,X).
#show drive/1
The answer is: drive(potsdam), drive(werder), drive(berlin).
In Prolog, I initially thought it would be as simple as changing the not to \+. When I query drive(X)., it recursively generates the X = potsdam answer. I know that Prolog and ASP work differently but I just can't figure it out.

The problem is road(X,Y) :- road(Y,X). This will recurse forever if there is no match among the facts:
is road(X,Y)?
is road(Y,X)?
is road(X,Y)?
is road(Y,X)?
.....
You can replace the predicate:
road(X,Y) :- road(Y,X).
with
road(X,X).
and add:
reachable(X,Y):-
road(X,Y)
; road(Y,X).
and modify:
route(X,Y) :- road(X,Y), \+ blocked(X,Y).
to:
route(X,Y) :- reachable(X,Y), \+ blocked(X,Y).

Related

Expanding Prolog clauses without parameters

I am writing a program that transforms other programs by expanding predicates. I usually do this using clause/2, but it doesn't always expand a predicate if it has no parameters:
:- set_prolog_flag('double_quotes','chars').
:- initialization(main).
main :- clause(thing,C),writeln(C).
% this prints "true" instead of "A = 1"
thing :- A = 1.
Is it possible to expand predicates that have no parameters?
Some general remark: Note that this code is highly specific to SWI. In other systems which are ISO conforming you can only access definitions via clause/2, if that predicate happens to be dynamic.
For SWI, say listing. to see what is happening.
?- assert(( thing :- A = 1 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
true.
?- assert(( thing :- p(A) = p(1) )).
true.
?- assert(( thing(X) :- Y = 2 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
thing :-
p(_)=p(1).
:- dynamic thing/1.
thing(_).
true.
It all looks like some tiny source level optimization.

How to define `not_a_parent()` predicate?

How to create such logic in GNU Prolog? How to define not_a_parent() predicate?
parent(john,chris).
parent(mary,chris).
not_a_parent(X) :- \+ parent(X,Y).
The interesting answer to the similar question is What is the logical 'not' in Prolog?. But I do not see how to implement it here.
This worked for me:
parent(john,chris).
parent(mary,chris).
parent(mary,suzanne).
parent(suzanne,jane).
parent(suzanne,peter).
parent(peter,rose).
parent(jerry,rose).
parent(jane,carl).
not_a_parent(NonParents) :- setof(Z,Y^parent(Y,Z),SetOfChildren),
findNonParents(SetOfChildren, NonParents, []),!.
findNonParents([],A,A).
findNonParents([H|SetOfChildren], NonParents, A):-
not(call(parent(H,_))),
findNonParents(SetOfChildren,NonParents,[H|A]).
findNonParents([_|SetOfChildren], NonParents, A):-
findNonParents(SetOfChildren,NonParents,A).
Result for querying not_a_parent(NonParents) is:
?- not_a_parent(NonParents).
NonParents = [rose, chris, carl].
You need to enumerate all the persons somehow. For example
not_a_parent(X) :- ( X = john ; X = mary ; X = chris ), \+ parent(X,_).
In any real program you would probably have some simple way to get all persons, and then you can do
not_a_parent(X) :- person(X), \+ parent(X,_).
You need to get all the instances of parent/2 such that X never unifies parent(X,_). findall(Template, Goal, Instances) executes the Goal until it fails and populate the list Instances with the terms that unify the Template. That way, if the list Instances is empty then parent(X,_) does not exist.
So your predicate would be like:
not_a_parent(X):- findall(_, parent(X,_) , []).

Prolog rewriting equations

I am trying to create a rewrite predicate in SWI-Prolog that checks if an equation can be simplified then replaces the old one with the new one. I have tried to do the following:
Lets say I have the following equation x+0 and I want to replace/rewrite it with x.
I have tried the following:
simplify(X,X) :- primitive(X).
simplify(X,Y) :- evaluable(X), Y is X.
simplify_exp(X,Y) :- rewrite(X,X1), simplify(X1,Y).
simplify_exp(X,X).
primitive(X) :- atom(X).
rewrite(X+0,X).
rewrite(0+X,X).
rewrite(x+1+(y-1),x+y).
rewrite(X*X,X^2).
rewrite(X^0,1).
rewrite(0*X,0).
rewrite(X*N,N*X) :- number(N).
simplify(X) will return x to me, then I need to rewrite which is fine.
However when I have a longer equation lets say (power(a)+b)-(x+0), it won't find simplify(X) hence I cannot rewrite it.
Can I get any recommendation/help please?
The rewrite predicate can be re-written more concisely:
:- initialization(main).
:- set_prolog_flag(double_quotes, chars).
main :- rewrite(x*0,Output),writeln(Output).
rewrite(X+0,X1) :- rewrite(X,X1).
rewrite(0+X,X+0).
rewrite(X,X) :- atom(X);number(X).
rewrite(X+1+(Y-1),X1+Y1) :- rewrite(X,X1),rewrite(Y,Y1).
rewrite(X*X,X1^2) :- rewrite(X,X1).
rewrite(X^0,1).
rewrite(0*X,0).
rewrite(X*0,Output) :- rewrite(0*X,Output).
rewrite(X*N,N*X1) :- number(N),(\+number(X)),rewrite(X,X1).
rewrite(N*X,N*X1) :- rewrite(X*N,N*X1).
To simplify more complicated arithmetic expressions, you can use the Reduce-Algebraic-Expressions library.

Variables for predicates in metagol

The following program noMetagolR is given in:
http://www.doc.ic.ac.uk/~shm/Papers/metagol_gram.pdf page 33.
parse(S,G1,G2) :- parse(s(0),S,[],G1,G2).
parse(Q,X,X,G1,G2) :- abduce(acceptor(Q),G1,G2).
parse(Q,[C|X],Y,G1,G2) :- Skolem(P), abduce(delta1(Q,C,P),G1,G3), parse(P,X,Y,G3,G2).
abduce(X,G,G) :- member(X,G).
abduce(X,G,[X|G]) :- not(member(X,G)).
Skolem(s(0)). Skolem(s(1)). ...
An example query is :
parse([],[],G1), parse([0],G1,G2), parse([0,0],G2,G3), parse([1,1],G3,G4), parse([0,0,0],G4,G5), parse([0,1,1],G5,G6), parse([1,0,1],G6,G),not(parse([1],G,G)), not(parse([0,1],G,G)).
The answer substitutions should return a learnt grammar for parity.
The program is said to run in Yap. I normally use SWI-prolog. Either way,
what do I do to make them understand Skolem/1 ? Presumbly this means that Skolem is a variable? I thought maybe using =.. but this does not work.
Also how many Skolem/1 facts are needed?
in SWI-Prolog, you can place in your source the directive
:- set_prolog_flag(allow_variable_name_as_functor,true).
see current_prolog_flag/2
example on REPL:
1 ?- set_prolog_flag(allow_variable_name_as_functor,true).
true.
2 ?- assert(X(1)).
true.
3 ?- X(Y).
Y = 1.

Help with simple prolog exercise

I haven't been able to solve this prolog exercise. I was hoping someone here could give me some hints or post a solution. Thanks in advance.
Database:
lig(super, porto).
lig(super, benfica).
lig(super, sporting).
lig(honra, feirense).
lig(honra, guimaraes).
jog(sporting, ricardo, gr).
jog(guimaraes, cleber, de).
jog(feirense, edgar, me).
jog(porto, quaresma, av).
jog(porto, helton, gr).
jog(benfica, simao, av).
jog(sporting, moutinho, me).
The sample output:
?- calcula(Lista).
Lista = [super-[porto-[quaresma,helton], benfica-[simao], sporting-
[moutinho,ricardo]], honra-[ feirense-[edgar], guimarĂ£es-[cleber]]].
My procedure:
calcula(Lista) :-
findall(Lig-[Eq-[X]],
(lig(Lig, Eq), findall(Jog, jog(Eq, Jog, _), X)),
Lista).
My output (which is wrong!).
Lista = [super-[porto-[[quaresma, helton]]], super-[benfica-[[simao]]], super-[sporting-[[ricardo, moutinho]]], honra-[feirense-[[edgar]]]
I see in the zfm's solution, the predicate lig(Lig, _) becomes true 5 times so there is some duplication in the final list. You can use the predicate setof/3 and existential quantified variable Eq0^ to remove duplication:
calcula(T) :- setof(Lig-X, Eq0^(lig(Lig, Eq0),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T).
Since I'm so interested to the question, I try it a lot.
Well, this is, I believe, not the best answer. However I get the result.
calcula(Ans):-findall(Lig-X, (lig(Lig, _),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T),
removeEq(T,Ans).
removeEq([A-B,A-_|Tail], [A-B|TailChanged]) :- !, removeEq([A-B|Tail],
[A-B|TailChanged]).
removeEq([A-B,C-D|Tail], [A-B,C-D|TailChanged]) :- removeEq([A-B|Tail],
[A-B|TailTemp]), removeEq([C-D|TailTemp], [C-D|TailChanged]).
removeEq([X], [X]).
The removeEq is needed because there are duplicated answer (I don't know how not to duplicate it)
This is not shorter than zfm's answer, but it is "simpler" in the way that it only uses basic prolog constructs to construct the list directly. (No removal of duplicates afterward.) There is some code duplication which probably could be gotten rid of to get a shorter answer.
g(Second, [Third|Rest], Done) :- jog(Second, Third,_),
not(member(Third, Done)),!,
g(Second, Rest, [Third|Done]).
g(_,[],_).
f(First, [Second-New|Rest], Done) :- lig(First, Second),
not(member(Second, Done)),!,
g(Second, New, []),
f(First, Rest, [Second|Done]).
f(_,[],_).
h([First-X|Lista], Done):-
lig(First,_),
not(member(First, Done)),!,
f(First, X, []),
h(Lista,[First|Done]).
h([], _).
calcula(X) :- h(X, []).

Resources