Prolog rewriting equations - prolog

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.

Related

Prolog remove parenthesis when transforming list in polynomial

Basically when I try to transform a list into a polynomial or vice-versa, it always shows up with parenthesis (in case of the polynomials). Here is the code, the function not working is the poly2list, the other one are just to define what a monomial/polinomial is.
pvars([x,y,z]).
pvar(X):-pvars(V),member(X,V).
polinomial(X) :- monomial(X).
polinomial(P+M) :- monomial(M), polinomial(P).
monomial(X) :- pvar(X).
monomial(N) :- number(N).
monomial(X) :- power(X),!.
monomial(K*X) :- coefficient(K), power(X),!.
coefficient(N) :- number(N).
power(X) :- pvar(X),!.
power(X^Y) :- pvar(X), integer(Y), Y>1,!.
poly2list(X,[X]) :- monomial(X),!.
poly2list(X+P,[X|Y]) :- monomial(X), poly2list(P,Y).
For example, when i ask:
poly2list(X,[2*x^2,3,y]).
The result is:
X = 2*x^2+(3+y)
And I'm trying to get:
X = 2*x^2+3+y
Thanks in advance :)

Prolog - ASP 'not' to Prolog negate

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).

Match database items exactly once in Prolog?

Let's say there is a simple database of people in Prolog
person(john).
person(mary).
person(john).
person(susan).
I need to match the entires exactly once:
john-mary, john-john, john-susan, mary-john, mary-susan, john-susan
I tried coming up with something like this:
match:- person(X),!,person(Y), write(X),write(-), write(Y),nl.
run:- person(X), match(X), fail.
But it's matching many times, and matches a person to him/herself, which shouldn't be.
Basically, what I need is to iterate over all Xs and make Prolog to look strictly "below" for Ys.
A quick solution would be to number your people:
person(1, john).
person(2, mary).
person(3, john).
person(4, susan).
Then you could match people like this:
match(X-Y) :-
person(I, X), person(J, Y), I < J.
Since you have two john entries, I'm not sure any other solution is going to work. Normally you could fake an ordering using #>/2 but that would require your atoms to be unique, and since they aren't, it would prevent the john-john solution.
Edit: Since we're willing to use findall/3 to materialize the database of people, we can treat this as a list problem and find a functional solution. Let's get all the combinations in a list:
combinations([X|Rest], X, Y) :- member(Y, Rest).
combinations([_|Rest], X, Y) :- combinations(Rest, X, Y).
With this predicate in hand, we can find the solution:
combined_folks(People) :-
findall(P, person(P), Persons),
findall(X-Y, combinations(Persons, X, Y), People).
?- combined_folks(X).
X = [john-mary, john-john, john-susan, mary-john, mary-susan, john-susan].
That actually turned out to be pretty clean!
person(john).
person(mary).
person(john).
person(susan).
match :- findall(P,person(P),People), match_all(People).
match_all([_]) :- !.
match_all([P|People]) :- match_2(P,People), match_all(People).
match_2(_,[]) :- !.
match_2(P1,[P2|People]) :- format('~a-~a~n',[P1,P2]), match_2(P1,People).
?- match.

how can I make prolog print query results when running a prolog script

I'm new to prolog and want to save all queries in a file instead of typing them by hand.
I have these facts in facts.pl:
likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).
friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
After reading the answer of this question,
I come up with the following code queries.pl:
main :-
write(likes(wallace, cheese)),
halt.
:- initialization(['facts.pl']).
:- initialization(main).
Here I want to examine if likes(wallace, cheese) holds,
what I expected is outputing something like yes or no but the actual output is likes(wallace, cheese)
I've googled a lot and attempted
X = likes(wallace, cheese), write(X).
X is likes(wallace, cheese), write(X).
X := likes(wallace, cheese), write(X).
but none of them works.
It might be a really easy question for you, but I have no idea about how to get things right.
BTW, I'm using GNU Prolog 1.4.1
I think you need a way to 'tag' each query: here a simple way
query(likes(wallace, cheese)).
query(likes(mickey, whisky)).
% service predicates, check the library and use that if available
forall(X,Y) :- \+ (X, \+ Y).
writeln(T) :- write(T), nl.
main :-
forall(query(Q), (Q -> writeln(yes:Q) ; writeln(no:Q))),
halt.

Searching Prolog structures

I'm interested in formulae made up from lots of conjunctions (part of a larger problem). I want to write a program that takes something like this:
:- get_params(conj(conj(a,b),c),X)
and returns a list of all the parameters of the conjunctions i.e. X=[a,b,c]. At the moment I can do
:- get_params(conj(a,b),X) to get X=[a,b]
using simple Prolog pattern matching but how would you go about doing things such as
:- get_params(conj(conj(a,b),c),X) to get X=[a,b,c]
It seems really simple but I've been struggling all day!
Since you are describing a list, consider using DCG notation:
params(conj(A,B)) --> !, params(A), params(B).
params(X) --> [X].
Example:
?- phrase(params(conj(conj(a,b),c)), Ps).
Ps = [a, b, c].
Assuming that all conj functors are binary:
get_params(X, Y, L) :-
get_params(X, L1),
get_params(Y, L2),
append(L1, L2, L).
get_params(conj(X, Y), L) :-
get_params(X, Y, L), !.
get_params(A, [A]).

Resources