Prolog's built-in reverse function acting odd - prolog

Given the following code:
fun(a, [b]).
fun(b, [c]).
fun(c, [d]).
fun(d, [e]).
fun(e, []).
xyz(X, Y):-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,F), sort(F,J), reverse(J,Y); Y = [].
With the query xyz(a,X) I get the expected output X = [e,d,c,b]..
What could possibly be throwing this off? Does this have to do with the sort function? If so, according to the documents in the links below, alpha or numeric order of precedence could be throwing this off, but it still doesn't explain by cs40 is going before cs30. I am having a hard time finding a correlation. How can I fix this issue?
http://www.swi-prolog.org/pldoc/doc_for?object=sort/2
http://www.swi-prolog.org/pldoc/man?section=compare
By the way, the fun function could have multi-element lists such as fun(a, [b,c], where a has multiple dependencies b and c. This aspect shouldn't matter too much regarding the current issue that I have, but just getting this fact out there.
UPDATE
Thanks to #lurker, I've made some great progress.
Given the following code:
final_xyz(X, Y):- xyz(X, R), reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
In an attempt to fix this, I updated the code to:
xyz-final(X,Y):-
fun(X,Z),
Z\=0,
( length(Z,1) -> xyz(X,J), reverse(J,Y)
;
xyz2(X,B), sort(B,C), reverse(C,Y)
).
xyz(K, [X|Y]):- fun(K, [X]), !, xyz(X, Y).
xyz(_, []).
xyz2(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz2(A,B)), L),
flatten(L,Y); Y = [].
Very clumsy approach, but this seems to work for me now. I'll work on making it more efficient.

The issue is that you are wanting to reverse the final result, but your reverse is being done in each recursive call to xyz/2. If you do a trace on your xyz(cs140a, X) call, you'll see it's being called a few times on different recursions.
If you want it once at the end, then you can write it this way:
final_xyz(X, Y) :-
xyz(X, R),
reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
And then calling final_xyz(cs140a, X) yields, X = [m16a,cs30,cs40,cs110].
Here's an alternative approach to your xyz predicate which avoids the findall and the flatten. This version should avoid cyclical paths and doesn't show duplicates:
xyz(X, Y) :-
fun(X, L),
xyz(L, [], R),
reverse(R, Y).
xyz([H|T], A, R) :-
( memberchk(H, A)
-> xyz(T, A, R)
; fun(H, L)
-> xyz(L, [H|A], R1),
xyz(T, R1, R)
; xyz(T, [H|A], R)
).
xyz([], A, A).

Related

How do I use rule in another rule in prolog

Here are my facts:
object('Human').
object('Machine').
object('Robot').
object('Hunter').
object('WallE').
action('Kill').
action('Run').
rel1('Hunter', 'Human').
rel1('Robot', 'Machine').
rel1('WallE', 'Robot').
rel2('Human', 'Run').
rel2('Machine', 'Run').
rel2('Robot', 'Kill').
I'm trying to find the list of all object that implement a given action. So for example if I run this:
?-provides_action(’Run’, X).
It gives the result:
X = [’Human’, ’Machine’, ’Hunter’, ’Robot’, ’WallE’].
OR
?-provides_action(’Kill’, X).
It gives the result:
X = ['WallE'].
I have tried this
provides_action2(X, L) :- findall(Y, (rel2(Y,X)),L).
provides_action3(X, L) :- provides_action2(X, L1), findall(Z, rel1(Z,L1), L2), append(L1,L2,L).
It doesnt give me the correct answer, I want to use the result from the first rule (L1) and use it in the 2nd findall extends(Z,L1) but it doesnt seem to do that.
Could anyone please explain to me what's wrong?
Thank you in advance!
First, you must define predicate extends/2 using rel1/2:
extends(A, C) :- rel1(A, C).
extends(A, C) :- rel1(A, B), extends(B, C).
Examples:
?- extends(X, 'Human').
X = 'Hunter' ;
false.
?- extends(X, 'Machine').
X = 'Robot' ;
X = 'WallE' ;
false.
After, you can use this predicate to define provides_action/2, as following:
provides_action(X, L) :-
findall(Y, rel2(Y,X), L1),
findall(C, (member(A, L1), extends(C, A)), L2),
append(L1, L2, L).
Notice that member(A, L1) is needed to iterate list L1.
Running example:
?- provides_action('Run', L).
L = ['Human', 'Machine', 'Hunter', 'Robot', 'WallE'].

Can single sided unification improve error handling?

Inspired by this question, I am trying to harden error
handling of reverse/2. So I tried this implementation:
reverse(X, Y) :- reverse(X, [], Y).
reverse(X, _, _) :- var(X), throw(error(instantiation_error,_)).
reverse([], X, R) :- !, R = X.
reverse([X|Y], Z, R) :- !, reverse(Y, [X|Z], R).
reverse(X, _, _) :- throw(error(type_error(list,X),_)).
Everything works fine, until I try reverse/2 as a generator:
?- reverse([1,2,3],X).
X = [3, 2, 1].
?- reverse(2,X).
ERROR: Type error: `list' expected, found `2' (an integer)
?- reverse(X,Y).
ERROR: Arguments are not sufficiently instantiated
Can single sided unification change the situation, some typical solution based on single sided unification so that the generator reverse(X,Y) would still work? Single sided unification is available in SWI-Prolog 8.3.19.
I am afraid I cannot present a single sided unification solution. Its rather that normal unification in the form of (\=)/2 could be useful. I hardly use (\=)/2 ever. The solution is inspired by Dijkstra guards if-fi, link to paper at end of this post:
if
Cond1 -> ActionList1
..
Condn -> ActionList2
fi
The if-fi aborts if none of the conditions Cond1,..,Condn is satisfied. So we
simply use a conjunction of the negation of the conditions:
reverse(X, Y) :- reverse(X, [], Y).
reverse(X, _, _) :- X \= [], X \= [_|_], throw(error(type_error(list,X),_)).
reverse([], X, R) :- R = X.
reverse([X|Y], Z, R) :- reverse(Y, [X|Z], R).
Seems to work:
?- reverse([1,2,3],X).
X = [3, 2, 1].
?- reverse(2,X).
ERROR: Type error: `list' expected, found `2' (an integer)
?- reverse(X,Y).
X = Y, Y = [] ;
X = Y, Y = [_1778] ;
X = [_1778, _2648],
Y = [_2648, _1778] ;
Etc..
So single sided unification might be the wrong approach? I dont know. The above solution incures an overhead, unless some indexing might optimize away (\=)/2. Could even work in connection with attributed variables.
Nondeterminacy and Formal Derivation of Programs
Edsger W. Dijkstra - Burroughs Corporation
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.90.97&rep=rep1&type=pdf
This seems to work (a straightforward translation to use => of reverse/2 in library(lists)):
reverse(List, Reversed) =>
reverse(List, [], Reversed, Reversed).
reverse([], Ys, Reversed, Tail) =>
Reversed = Ys,
Tail = [].
reverse([X|Xs], Rs, Reversed, Tail) =>
Tail = [_|Bound],
reverse(Xs, [X|Rs], Reversed, Bound).

How to evaluate a variable with string value?

My code does perfect with numbers, but error with single quotation. I'm trying to write a foldl function. When i do foldl1(concat, ['a','b'], X), it reports like "ERROR: Arithmetic: 'ab/0' is not a function". what is the problem? prolog does not allow using is with string?
foldl1(P, [H], X) :-
X is H.
foldl1(P, [H|T], X) :-
foldl1(P, T, Y),
call(P, H, Y, Z),
X is Z.
is/2 evaluates the arithmetic expression to the right, and unifies the result with the term to the left. Unification is also performed against the head' arguments, so you can write a simplified foldl1/3 like
foldl1(_, [H], H).
foldl1(P, [H|T], Z) :-
foldl1(P, T, Y),
call(P, H, Y, Z).
test:
?- foldl1(plus,[1,2,3],R).
R = 6 ;
false.
?- foldl1(concat,[1,2,3],R).
R = '123' ;
false.
I would place a cut after the recursion base, since [H] and [H|T] where T=[] overlap, to avoid any last call - that would anyway fail - on eventual backtracking, like the redo induced by me, inputting ; after the expected first answer while the interpreter waits for my choices.
After the cut (hope you can easily spot where to place it) we get:
?- foldl1(plus,[1,2,3],R).
R = 6.
?- foldl1(concat,[1,2,3],R).
R = '123'.
Now the interpreter 'knows' there are no more answers after the first...
It's also possible to implement a foldl1/3 predicate using first-argument indexing to avoid spurious choice-points without cuts and that is also tail-recursive. From the Logtalk library meta object:
:- meta_predicate(foldl1(3, *, *)).
foldl1(Closure, [Head| Tail], Result) :-
fold_left_(Tail, Closure, Head, Result).
fold_left_([], _, Result, Result).
fold_left_([Arg| Args], Closure, Acc, Result) :-
call(Closure, Acc, Arg, Acc2),
fold_left_(Args, Closure, Acc2, Result).
Sample calls:
?- meta::foldl1(plus,[1,2,3],R).
R = 6.
?- meta::foldl1(concat,[1,2,3],R).
R = '123'.

Write a Prolog predicate next(X,List,List1)

Prolog predicate next(X, List,List1), that returns in List1 the next element(s) from List that follows X, e.g., next(a,[a,b,c,a,d],List1), will return List1=[b,d].
I have tried following:
next(X, [X,Y|List], [Y|List1]) :- % X is the head of the list
next(X, [Y|List], List1).
next(X, [Y|List], List1) :- % X is not the head of the list
X \== Y,
next(X, List, List1).
next(_,[], []).
First, whenever possible, use prolog-dif for expressing term inequality!
Second, the question you asked is vague about corner cases: In particular, it is not clear how next(E,Xs,Ys) should behave if there are multiple neighboring Es in Xs or if Xs ends with E.
That being said, here's my shot at your problem:
next(E,Xs,Ys) :-
list_item_nexts(Xs,E,Ys).
list_item_nexts([],_,[]).
list_item_nexts([E],E,[]).
list_item_nexts([I|Xs],E,Ys) :-
dif(E,I),
list_item_nexts(Xs,E,Ys).
list_item_nexts([E,X|Xs],E,[X|Ys]) :-
list_item_nexts(Xs,E,Ys).
Let's see some queries!
?- next(a,[a,b,c,a,d],List1).
List1 = [b,d] ;
false.
?- next(a,[a,a,b,c,a,d],List1).
List1 = [a,d] ;
false.
?- next(a,[a,a,b,c,a,d,a],List1).
List1 = [a,d] ;
false.
Note that above queries succeed, but leave behind useless choicepoints.
This inefficiency can be dealt with, but I suggest figuring out more complete specs first:)
This version is deterministic for the cases given by #repeat using if_/3 and (=)/3. It shows how purity and efficiency can coexist in one and the same Prolog program.
next(E, Xs, Ys) :-
xs_e_(Xs, E, Ys).
xs_e_([], _E, []).
xs_e_([X|Xs], E, Ys) :-
if_(X = E, xs_e_xys(Xs, E, Ys), xs_e_(Xs, E, Ys)).
xs_e_xys([], _E, []).
xs_e_xys([X|Xs], E, [X|Ys]) :-
xs_e_(Xs, E, Ys).
%xs_e_xys([X|Xs], E, [X|Ys]) :- % alternate interpretation
% xs_e_([X|Xs], E, Ys).

Prolog. How to check if two math expressions are the same

I'm writing a prolog program that will check if two math expressions are actually the same. For example, if my math expression goal is: (a + b) + c then any of the following expressions are considered the same:
(a+b)+c
a+(b+c)
(b+a)+c
(c+a)+b
a+(c+b)
c+(a+b)
and other combinations
Certainly, I don't expect to check the combination of possible answers because the expression can be more complex than that.
Currently, this is my approach:
For example, if I want to check if a + b *c is the same with another expression such as c*b+a, then I store both expression recursively as binary expressions, and I should create a rule such as ValueOf that will give me the "value" of the first expression and the second expression. Then I just check if the "value" of both expression are the same, then I can say that both expression are the same. Problem is, because the content of the expression is not number, but identifier, I cannot use the prolog "is" keyword to get the value.
Any suggestion?
many thanks
% represent a + b * c
binExprID(binEx1).
hasLeftArg(binEx1, a).
hasRightArg(binEx1, binEx2).
hasOperator(binEx1, +).
binExprID(binEx2).
hasLeftArg(binEx2, b).
hasRightArg(binEx2, c).
hasOperator(binEx2, *).
% represent c * b + a
binExprID(binEx3).
hasLeftArg(binEx3, c).
hasRightArg(binEx3, b).
hasOperator(binEx3, *).
binExprID(binEx4).
hasLeftArg(binEx4, binEx3).
hasRightArg(binEx4, a).
hasOperator(binEx4, +).
goal:- valueOf(binEx1, V),
valueOf(binEx4, V).
Math expressions can be very complex, I presume you are referring to arithmetic instead. The normal form (I hope my wording is appropriate) is 'sum of monomials'.
Anyway, it's not an easy task to solve generally, and there is an ambiguity in your request: 2 expressions can be syntactically different (i.e. their syntax tree differ) but still have the same value. Obviously this is due to operations that leave unchanged the value, like adding/subtracting 0.
From your description, I presume that you are interested in 'evaluated' identity. Then you could normalize both expressions, before comparing for equality.
To evaluate syntactical identity, I would remove all parenthesis, 'distributing' factors over addends. The expression become a list of multiplicative terms. Essentially, we get a list of list, that can be sorted without changing the 'value'.
After the expression has been flattened, all multiplicative constants must be accumulated.
a simplified example:
a+(b+c)*5 will be [[1,a],[b,5],[c,5]] while a+5*(c+b) will be [[1,a],[5,c],[5,b]]
edit after some improvement, here is a very essential normalization procedure:
:- [library(apply)].
arith_equivalence(E1, E2) :-
normalize(E1, N),
normalize(E2, N).
normalize(E, N) :-
distribute(E, D),
sortex(D, N).
distribute(A, [[1, A]]) :- atom(A).
distribute(N, [[1, N]]) :- number(N).
distribute(X * Y, L) :-
distribute(X, Xn),
distribute(Y, Yn),
% distribute over factors
findall(Mono, (member(Xm, Xn), member(Ym, Yn), append(Xm, Ym, Mono)), L).
distribute(X + Y, L) :-
distribute(X, Xn),
distribute(Y, Yn),
append(Xn, Yn, L).
sortex(L, R) :-
maplist(msort, L, T),
maplist(accum, T, A),
sumeqfac(A, Z),
exclude(zero, Z, S),
msort(S, R).
accum(T2, [Total|Symbols]) :-
include(number, T2, Numbers),
foldl(mul, Numbers, 1, Total),
exclude(number, T2, Symbols).
sumeqfac([[N|F]|Fs], S) :-
select([M|F], Fs, Rs),
X is N+M,
!, sumeqfac([[X|F]|Rs], S).
sumeqfac([F|Fs], [F|Rs]) :-
sumeqfac(Fs, Rs).
sumeqfac([], []).
zero([0|_]).
mul(X, Y, Z) :- Z is X * Y.
Some test:
?- arith_equivalence(a+(b+c), (a+c)+b).
true .
?- arith_equivalence(a+b*c+0*77, c*b+a*1).
true .
?- arith_equivalence(a+a+a, a*3).
true .
I've used some SWI-Prolog builtin, like include/3, exclude/3, foldl/5, and msort/2 to avoid losing duplicates.
These are basic list manipulation builtins, easily implemented if your system doesn't have them.
edit
foldl/4 as defined in SWI-Prolog apply.pl:
:- meta_predicate
foldl(3, +, +, -).
foldl(Goal, List, V0, V) :-
foldl_(List, Goal, V0, V).
foldl_([], _, V, V).
foldl_([H|T], Goal, V0, V) :-
call(Goal, H, V0, V1),
foldl_(T, Goal, V1, V).
handling division
Division introduces some complexity, but this should be expected. After all, it introduces a full class of numbers: rationals.
Here are the modified predicates, but I think that the code will need much more debug. So I allegate also the 'unit test' of what this micro rewrite system can solve. Also note that I didn't introduce the negation by myself. I hope you can work out any required modification.
/* File: arith_equivalence.pl
Author: Carlo,,,
Created: Oct 3 2012
Purpose: answer to http://stackoverflow.com/q/12665359/874024
How to check if two math expressions are the same?
I warned that generalizing could be a though task :) See the edit.
*/
:- module(arith_equivalence,
[arith_equivalence/2,
normalize/2,
distribute/2,
sortex/2
]).
:- [library(apply)].
arith_equivalence(E1, E2) :-
normalize(E1, N),
normalize(E2, N), !.
normalize(E, N) :-
distribute(E, D),
sortex(D, N).
distribute(A, [[1, A]]) :- atom(A).
distribute(N, [[N]]) :- number(N).
distribute(X * Y, L) :-
distribute(X, Xn),
distribute(Y, Yn),
% distribute over factors
findall(Mono, (member(Xm, Xn), member(Ym, Yn), append(Xm, Ym, Mono)), L).
distribute(X / Y, L) :-
normalize(X, Xn),
normalize(Y, Yn),
divide(Xn, Yn, L).
distribute(X + Y, L) :-
distribute(X, Xn),
distribute(Y, Yn),
append(Xn, Yn, L).
sortex(L, R) :-
maplist(dsort, L, T),
maplist(accum, T, A),
sumeqfac(A, Z),
exclude(zero, Z, S),
msort(S, R).
dsort(L, S) :- is_list(L) -> msort(L, S) ; L = S.
divide([], _, []).
divide([N|Nr], D, [R|Rs]) :-
( N = [Nn|Ns],
D = [[Dn|Ds]]
-> Q is Nn/Dn, % denominator is monomial
remove_common(Ns, Ds, Ar, Br),
( Br = []
-> R = [Q|Ar]
; R = [Q|Ar]/[1|Br]
)
; R = [N/D] % no simplification available
),
divide(Nr, D, Rs).
remove_common(As, [], As, []) :- !.
remove_common([], Bs, [], Bs).
remove_common([A|As], Bs, Ar, Br) :-
select(A, Bs, Bt),
!, remove_common(As, Bt, Ar, Br).
remove_common([A|As], Bs, [A|Ar], Br) :-
remove_common(As, Bs, Ar, Br).
accum(T, [Total|Symbols]) :-
partition(number, T, Numbers, Symbols),
foldl(mul, Numbers, 1, Total), !.
accum(T, T).
sumeqfac([[N|F]|Fs], S) :-
select([M|F], Fs, Rs),
X is N+M,
!, sumeqfac([[X|F]|Rs], S).
sumeqfac([F|Fs], [F|Rs]) :-
sumeqfac(Fs, Rs).
sumeqfac([], []).
zero([0|_]).
mul(X, Y, Z) :- Z is X * Y.
:- begin_tests(arith_equivalence).
test(1) :-
arith_equivalence(a+(b+c), (a+c)+b).
test(2) :-
arith_equivalence(a+b*c+0*77, c*b+a*1).
test(3) :-
arith_equivalence(a+a+a, a*3).
test(4) :-
arith_equivalence((1+1)/x, 2/x).
test(5) :-
arith_equivalence(1/x+1, (1+x)/x).
test(6) :-
arith_equivalence((x+a)/(x*x), 1/x + a/(x*x)).
:- end_tests(arith_equivalence).
running the unit test:
?- run_tests(arith_equivalence).
% PL-Unit: arith_equivalence ...... done
% All 6 tests passed
true.

Resources