Prolog: finding intersection of two lists? - prolog

Let's say I have Prolog facts such as:
fact1(x, [y1, y2, y3, y4]).
fact2(z1, [s, t, u, **y3**).
fact2(z2, [o, p, **y1**, q, r]).
fact2(z3, [**y1**, m, **y3**, n]).
fact2(z4, [j, k, **y4**, l]).
fact2(z5, [**y2**, d, e, f, g, h, i]).
fact2(z6, [a, b, c, **y4**]).
And, I want a query such that I get all the 'z' who are related to x.
Thus, this query should output z1, z2, z3, z4, z5, z6 because they all contain an element y1, y2, y3, and/or y4 because they are related to x in the first Prolog fact.
The following code outputs all of z's relation's of fact2:
fact2(_,X).
And the following code outputs x's relation of fact1:
fact1(x,X).
Thus, I figured that I would need to get the intersection of the two sets with the following code, but it doesn't work.
xyz(X):-
intersection(fact2(_,X),fact2(x,X),X).
This doesn't work, can someone lead me in the right direction?
With the query, what I need to get is: z1, z2, z3, z4, z5, z6 because they all contain either y1, y2, y3, and/or y4 due to the fact that those are all related to x int he first fact.
If you need clarification, please let me know. Thank you.

this snippet
xyz(L):-
fact1(x, L1),
setof(K, L2^I^(fact2(K, L2), intersection(L1,L2,I), I \= []), L).
yields
?- xyz(L).
L = [z1, z2, z3, z4, z5, z6].

You must instantiate each term on fact2 and fact1 in a different variable, otherwise you are forcing the instances to match identically. Also, lose the asterics on the facts "fact2", and close the clasp in the first fact "fact2", after the element y3.
If you wanna keep the asterics, then enclose them between single quotation mark.
fact1(x, [y1, y2, y3, y4]).
fact2(z1, [s, t, u, '**y3**']).
fact2(z2, [o, p, y1, q, r]).
fact2(z3, [y1, m, y3, n]).
fact2(z4, [j, k, y4, l]).
fact2(z5, [y2, d, e, f, g, h, i]).
fact2(z6, [a, b, c, y4]).
xyz(Z):- fact2(Z,X),fact1(_,Y), intersection(X,Y,I), I\=[].
Then try asking:
?- xyz(X)
or this if you want all the answers in a single list L:
?- setof(Z, xyz(Z), L).

Related

Compute addition and subtraction of an arithmetic expression without 'is'

How can I find the result of an arithmetic expression composed of pluses and minuses without using 'is'?
For example, to find the result of 1+2+3+4-6, I do: X is 1+2+3+4-6 and I get: X = 4.
What I've tried so far:
eval(EXPR, EXPR) :-
integer(EXPR),
!.
eval(X+Y, RES) :-
eval(X, X1),
eval(Y, Y1),
plus(X1, Y1, RES).
eval(X-Y, RES) :-
eval(X, X1),
eval(Y, Y1),
Y2 = -Y1,
plus(X1, Y2, RES).
but when I try to compute an expression containing negative numbers, I get the error: `integer' expected, found `- number` (a compound).
How can I solve it?
Add plus(Y1,Y2,0) instead of Y2 = -Y1.
In the latter case, Y2 is a structure with functor - and Argument Y1, whereas in the former case, Y1 is a number.
Take Y1 = 3 for example. [Just for fun: try it with Y1 = -3]
?- Y1 = 3, Y2 = -Y1, Y2 =.. L.
Y1 = 3,
Y2 = - 3,
L = [-, 3].
?- Y1 = 3, plus(Y1,Y2,0), Y2 =.. L.
Y1 = 3,
Y2 = -3,
L = [-3].
However, Y2 is supposed to be an argument in the predicate plus/3, which does not allow structures as arguments.
Maybe you prefer this solution:
eval(X-Y, RES) :-
eval(X, X1),
eval(Y, Y1),
plus(Y1, RES, X1).

Prolog Program not exiting

I've written prolog program which takes initial, pickup and final (x,y,z) coordinates. The agent should reach the final coordinates through the pickup coordinates. When I run the query, the program runs indefinitely. I'm assuming this is because there are a huge number of combinations to search through. So i decreased my constraints in in_range(X,Y,Z). I'm new to prolog, any help would be appreciated. Thanks
in_range(X,Y,Z):-
X > -5,
X < 5,
Y >= 0,
Y < 10,
Z > -5,
Z < 5.
deliver(Ix,Iy,Iz,Px,Py,Pz,Fx,Fy,Fz):-
in_range(Ix,Iy,Iz),
in_range(Px,Py,Pz),
in_range(Fx,Fy,Fz),
move(Ix,Iy,Iz,Px,Py,Pz),
move(Px,Py,Pz,Fx,Fy,Fz).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1-1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1-1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1-1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1-1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1,
Z is Z1-1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1,
Z is Z1-1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1+1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1+1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1+1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1+1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1,
Z is Z1+1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1,
Z is Z1+1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(6,_,_,_,_,_).
move(-6,_,_,_,_,_).
move(_,11,_,_,_,_).
move(_,-1,_,_,_,_).
move(_,_,6,_,_,_).
move(_,_,-6,_,_,_).
The query I'm running is
?-deliver(0,0,0,1,1,1,4,4,4).
You're hitting an infinite recursion because you're doing a depth-first search without tracking visited nodes, by tracing it you'll see for the example that your search gets lost in a (0, 0, 4) <> (0, 0, 5) loop, based on the first move predicate.
Tabling will work for SWI-Prolog, but let's take this opportunity to explore portable solutions as they'll aid your Prolog (and broader CS) learning.
First, let's look at that in_range/3 predicate and turn our locations into terms (if you bump into the word "reification", this is doing that). We want to consider our locations as terms so we can pass them around as whole entities. It also helps us think! We can define what a location is in your world like so:
% loc(X, Y, Z) is a location in 3D integer co-ordinate space
loc(X, Y, Z) :-
between(-5, 5, X),
between(0, 10, Y),
between(-5, 5, Z).
Thus in_range/3 becomes in_range/1:
in_range(Loc) :- call(Loc).
As a bonus, you can generate locations: ?- loc(X, Y, Z).
Now those move predicates can be tidied up to make them much easier to read, trace and think about. To that end, they only define a single move, best to keep journeys
to their own predicate so we can use these individually when we only want a single step. (?- move(loc(1, 1, 2), Step).)
%! move(Loc1, Loc2)
move(loc(X1, Y, Z), loc(X2, Y, Z)) :- X2 is X1 + 1, in_range(loc(X2, Y, Z)).
move(loc(X1, Y, Z), loc(X2, Y, Z)) :- X2 is X1 - 1, in_range(loc(X2, Y, Z)).
move(loc(X, Y1, Z), loc(X, Y2, Z)) :- Y2 is Y1 + 1, in_range(loc(X, Y2, Z)).
move(loc(X, Y1, Z), loc(X, Y2, Z)) :- Y2 is Y1 - 1, in_range(loc(X, Y2, Z)).
move(loc(X, Y, Z1), loc(X, Y, Z2)) :- Z2 is Z1 + 1, in_range(loc(X, Y, Z2)).
move(loc(X, Y, Z1), loc(X, Y, Z2)) :- Z2 is Z1 - 1, in_range(loc(X, Y, Z2)).
Now let's define our delivery predicate. in_range/1 can be used to check the From is valid, whereas Pickup and Dest are expected to take care of that themselves:
deliver(From, Pickup, Dest) :-
in_range(From),
go_to(From, Pickup),
go_to(Pickup, Dest).
So far I've only refactored your code to break predicates down into smaller definitions for more versatility and easier readability. The big change to prevent the infinite recursion is in go_to/2, which is not yet defined. Given that you're doing a search in integer 3D coordinate space, the most suitable search algorithm is A*, which will not only exclude search locations already visited, but will first search locations closest to the intended goal.
go_to(Origin, Destination) :-
a_star(Origin, Destination).
% A* for SWI-Prolog
:- use_module(library(heaps)).
% Use to order search, 3D euclidean distance squared
heuristic_distance(loc(X1, Y1, Z1), loc(X2, Y2, Z2), Distance) :-
Distance is (X1 - X2)^2 + (Y1 - Y2)^2 + (Z1 - Z2)^2.
% Add a list of nodes to the heap
open_add_nodes(Heap, [], _, Heap).
open_add_nodes(Heap, [ToAdd|Tail], Dest, Out) :-
heuristic_distance(ToAdd, Dest, Dist),
add_to_heap(Heap, Dist, ToAdd, Heap1),
open_add_nodes(Heap1, Tail, Dest, Out).
% Get an ordered list of reachable locations from the origin
get_reachable(Loc, Locations) :-
setof(L, move(Loc, L), Locations).
% A* search setup
a_star(Origin, Dest) :-
% Create heap of open search nodes
heuristic_distance(Dest, Origin, Dist),
singleton_heap(Open, Dist, Origin),
% Do the search
a_star(Open, Dest, [Origin]).
% Do the A* search
a_star(Open, Dest, Closed) :-
% Get the most promising Node
get_from_heap(Open, _, Loc, RemainingSearch),
% If we've reached the goal, return the Answer
( Dest = Loc
% Otherwise keep searching
; get_reachable(Loc, ReachableLocations),
% Exclude visited nodes
ord_union(Closed, ReachableLocations, Closed1, ToSearch),
% Add new open nodes to search heap
open_add_nodes(RemainingSearch, ToSearch, Dest, Open1),
% Carry on searching
a_star(Open1, Dest, Closed1)
).
Now A* might take a bit to read and understand, but it'd be much more difficult if we were having to deal with the X, Y, Z coordinates than with locations: every Loc, Dest, Origin and ToAdd is a location. It's also only possible to code because our move/2 predicate only takes a single step, so we can choose not to use Prolog's implicit Depth-First Search.
All this code is in a SWISH Notebook so you can explore it. To learn more about search algorithms I'd recommend the MIT AI lectures on YouTube, 4 and 5 cover search. For Prolog implementations, "The Craft of Prolog", also out of MIT, is excellent.

Multiple '\=' [Prolog]

How can I express the following conjunction more succinctly?
condition(X1, X2, X3, X4, X5) :-
X1 \= X2,
X1 \= X3,
X1 \= X4,
X1 \= X5,
X2 \= X3,
X2 \= X4,
X2 \= X5,
X3 \= X4,
X3 \= X5,
X4 \= X5.
Ideally, I want to use a single goal of a built-in / library predicate.
You could also opt to define a predicate uniques/1 with maplist/2 that succeeds if the list consists of unique elements. Then your predicate condition/5 would act as calling predicate:
:- use_module(library(apply)). % for maplist/2
condition(X1, X2, X3, X4, X5) :-
uniques([X1,X2,X3,X4,X5]).
uniques([]).
uniques([X|Xs]) :-
maplist(dif(X),Xs),
uniques(Xs).
?- condition(1,2,3,4,5).
true.
?- condition(1,2,3,4,1).
false.
And uniques/1 can be used for arbitrary lists:
?- uniques([]).
true.
?- uniques([1,a,6,f(X)]).
true.
?- uniques([A,B,C]).
dif(A, C),
dif(A, B),
dif(B, C).
?- uniques([A,B,A]).
false.
?- uniques(U).
U = [] ;
U = [_G265] ;
U = [_G392, _G395],
dif(_G392, _G395) ;
U = [_G489, _G492, _G495],
dif(_G489, _G495),
dif(_G489, _G492),
dif(_G492, _G495) ;
.
.
.
It depends...
If all Xi are integers and your Prolog supports finite-domain constraints (clpfd), just write:
:- use_module(library(clpfd)).
condition(X1, X2, X3, X4, X5) :-
all_distinct([X1,X2,X3,X4,X5]). % use library predicate

Assigning a value to a variable from a given list in Prolog

I want to assign a value to a variable, both are given in a list by my parser. So basically when I get [x, =, 2], I want to assign the value of 2 to x.
I am trying to do something like this, but it keeps popping out false:
assign_value(E, R) :-
\+ find(=, E, _),
R = E.
assign_value(E, R) :-
find(=, E, R1),
I1 is R1-1,
I2 is R1+1,
I3 is R1+2,
nth0(I1, E, P1),
nth0(I2, E, P2),
P1 is P2,
Result is P1,
length(E, Length),
extract(E, 0, I1, ListBefore),
extract(E, I3, Length, ListAfter),
append(ListBefore, [Result], Initial),
append(Initial, ListAfter, Final),
assign_value(Final, R).
Can anyone help? I'm a bit confused, as I am new to Prolog.

Transforming atoms in prolog variables

If I have a list of atoms, is it possible transform that in a list of prolog variables? If yes, anyone can give me an example?
Example:
?- atom_to_variable([x1, x2, x3], V).
V = [X1, X2, X3].

Resources