How can I assign variable X to only one thing in Prolog - prolog

I am writing a prolog code which has rooms and courses. A room can have multiple things such as a projector and smartboard and some of the courses needs these items.
%knowledge base
needs(101,projector).
needs(102,smart_board).
needs(241,smart_board).
needs(241,projector).
has(z23,projector).
has(z23,smart_board).
has(z06,projector).
has(z11,smart_board).
capacity(z06,50).
capacity(z11,70).
capacity(z23,90).
capacity(101,80).
capacity(102,70).
capacity(241,60).
capacity(341,40).
capacity(343,50).
%rules
assignRoom(C,R):- % C is a course, R is a Room
%course C can bi assigned to room R if:
((has(R,X),needs(C,X));%it needs 1 item and class has it or
(has(R,X),needs(C,X),has(R,Y),needs(C,Y)),X\=Y,%it needs 2 distinct items and class have both.
capacity(C, A), capacity(R, B), A=<B). %and the room can hold the number of students assigned to this course.
This code works for courses which needs one item only. But it doesn't work for courses which needs multiple items such as 241 because it holds for both conditions. How can I make the first condition checked if there is only one needs relation of the course.
Query for 102(correct):
?- assignRoom(102,X).
X = z23 ;
X = z11 ;
Query for 241(should be only z23):
?- assignRoom(241,X).
X = z23 ;
X = z23 ;
X = z11 ;
X = z23 ;
X = z23 ;

You could use forall/2 predicate.
forall(:Cond, :Action) For all alternative bindings of Cond, Action can be proven.
You can deal with all requirements in one statement.
assignRoom(C,R):-
capacity(C, A), capacity(R, B), A=<B,
forall(needs(C, X), has(R, X)).
?- assignRoom(241, X).
X = z23 ;
false.
?- assignRoom(102, X).
X = z11 ;
X = z23 ;
false.

Related

Check if a number is between 2 values

I am new to prolog and have am trying to write a program that will do the following tell me if a number is between 2 values I can do the following:
between(L, X, R) :-
X > L, X < R.
and doing between(1, 3, 5) works, but I would like it to be able to do between(1, X, 5) and have prolog return all the values in between so in this case X = 2, X = 3, X = 4, I get why my solution doesn't because it needs to be have been initialised, but I cannot think of a solution to this problem, can this type of thing just not be done in prolog?, and help would be great thanks
In case you don't want to predefine all numbers: let prolog create a list with possible entries and state your X has to be one of them. To understand the code you have to have knowledge about lists in prolog, especially Head and Tail notation of lists.
betweenList(L,R,[]):-
L>=R.
betweenList(L,R,[L|Rest]):-
L<R,
LL is L+1,
betweenList(LL,R,Rest).
between(L, X, R) :-
betweenList(L, R, [L| List]),
member(X, List).
?- between(1,X,5).
X = 2 ;
X = 3 ;
X = 4 ;
false.
betweenList(L,R,List) creates a List of all numbers between L and R, including L (as head element), excluding R. So if you want to generate a List without L, it is the easiest to just call betweenList(L, R, [L| List]) so List will not include L. Now X just has to be a member of List. The member/2 predicate can be easily written as well if you don't want to use the inbuild predicate.
One way to approach this:
digit(0).
digit(1).
digit(2).
digit(3).
digit(4).
digit(5).
digit(6).
digit(7).
digit(8).
digit(9).
between(L, X, U) :- digit(L), digit(X), digit(U), L < X, X < U.
Tests:
?- between(2, X, 5).
X = 3 ;
X = 4 ;
false.
?- between(2, 7, U).
U = 8 ;
U = 9.
Alternatively, you may want to look into Constraint logic programming.
Incidentally, Prolog already has a between/3:
?- between(1, 5, X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
although it's "illogical": you can't run it backwards, as the above definition.

Rule to test whether two lists contain same two elements fails due to uniqueness constraint

I'm trying to create a rule called redundancy that examines lists to see if two elements appear together in more than one list.
Here is my code:
columns([a,b,c]).
columns([b,c,d]).
in(X, [H|_]) :-
X = H.
in(X, [_|T]) :-
in(X, T).
redundancy(X, Y) :-
columns(A),
columns(B),
A \= B,
X \= Y,
in(X, A),
in(X, B),
in(Y, A),
in(Y, B).
The problem is the constraint X \= Y. I want it in there to exclude instances where X and Y are identical elements, which would be true for all single elements that appear in more than one list. But it only returns false for the given columns even though it should return permutations of b and c.
?- redundancy(U, T).
false.
If I comment out the constraint I get the expected elements along with the unwanted ones mentioned above.
?- redundancy(X, Y).
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
false.
Is there a way to enforce this constraint? I'm also interested in ideas to restrict results to a given combination of elements rather than permutations.
Simply move X \= Y to the last line of your predicate. also, see prolog-dif and instantiation-error.
The thing to avoid is using non-pure predicates with not-yet-instantiated logical variables (unless this is exactly what you intended, and you know what you're doing).
Another thing to notice is that X \= Y is not a constraint (that's dif), but a check.

Declarative uses of memberchk/2

memberchk/2 is a commonly defined predicate that is defined in terms of member/2 like so:
memberchk(X, Xs) :-
once(member(X, Xs)).
It therefore succeeds only for the first answer of member/2. Its full procedural meaning does not fit into a pure relation. As an example for its non-relational behavior consider
?- memberchk(b, [X,b]), X = a.
false.
?- X = a, memberchk(b, [X,b]).
X = a.
On the other hand, in many cases memberchk/2 will be called with sufficiently instantiated arguments, where it can be seen as an efficient approximation of a pure relation.
One such pure relation behind is memberd/2 (using if_/3):
memberd(E, [X|Xs]) :-
if_(E = X, true, memberd(E, Xs) ).
Are there any other pure relations that can be approximated by memberchk/2 for sufficiently instantiated cases?
In other words: Is memberd/2 a full, declarative replacement for memberchk/2 or are there still legitimate cases where memberchk/2 cannot be replaced by memberd/2?
Here is a well-known example use of member/2 that cannot be represented by memberd/2: bridge.pl the bridge scheduling problem given by Pascal Van Hentenryck.
In the setup phase member/2 is used:
setup(K,Ende,Disj):-
jobs(L),
make_vars(L,K),
member([stop,_,Ende],K),
....
So here, effectively the first element in the three-element list is used to select a particular task whereas memberd/2 uses the entire element for comparison. As a consequence this setup/3 leaves open a lot of choicepoints (actually, 219). Some (like SICStus) use memberchk/2 in that situation, thereby risking non-monotonicity.
Using the following pure replacement, all choicepoints are avoided.
member3l([N,D,A], Plan) :-
tmember(l3_t(N,D,A), Plan).
l3_t(N,D,A, X, T) :-
X = [Ni|_],
if_(N = Ni, ( X=[N,D,A], T = true ), T = false ).
tmember(P_2, [X|Xs]) :-
if_( call(P_2, X), true, tmember(P_2, Xs) ).
Alternatively using library(lambda):
member3li([N,Nd,Na], Plan) :-
tmember([N,Nd,Na]+\X^T^
( X=[Nk|_],
if_( Nk = N, ( X=[N,Nd,Na], T = true ), T = false ) ),
Plan).
Other uses of tmember/2:
old_member(X, Xs) :-
tmember( X+\E^T^( X = E, T = true ; T = false ), Xs).
old_memberd(X, Xs) :-
tmember(=(X), Xs).
Here is a more compact representation:
member3l([N,D,A], Plan) :-
tmember({N,D,A}+\[Ni,Di,Ai]^cond_t(N = Ni, [D,A] = [Di,Ai] ), Plan).
Using library(lambda)and cond_t/3:
cond_t(If_1, Then_0, T) :-
if_(If_1, ( Then_0, T = true ), T = false ).
The following answer does not directly relate to the original question regarding memberchk/2; instead, it is a follow-up to this previous answer which defined meta-predicate tmember/2.
We propose generalizing the idiom tmember/2 like so:
t_non_empty_suffix(P_3, [X|Xs]) :-
if_(call(P_3,Xs,X), true, t_non_empty_suffix(P_3,Xs)).
Building on t_non_empty_suffix/2 and Prolog lambdas, we can define tmemberX/2 like so:
:- use_module(library(lambda)).
tmemberX(P_2, Xs) :-
t_non_empty_suffix(P_2+\_^call(P_2), Xs).
The following old_memberX/2 and old_memberdX/2 use tmemberX/2 instead of tmember/2:
old_memberX(X, Xs) :-
tmemberX(X+\E^T^( X = E, T = true ; T = false ), Xs).
old_memberdX(X, Xs) :-
tmemberX(=(X), Xs).
Let's compare old_member/2 to old_memberX/2 ...
?- old_member(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.
?- old_memberX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.
... and old_memberd/2 to old_memberdX/2!
?- old_memberd(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.
?- old_memberdX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.
OK! How about defining old_member / old_memberd directly based on t_non_empty_suffix/2?
old_memberSFX(X, Xs) :-
t_non_empty_suffix(X+\_^E^T^( X = E, T = true ; T = false ), Xs).
old_memberdSFX(X, Xs) :-
t_non_empty_suffix(X+\_^E^( X = E ), Xs).
Running above queries with these predicates we get:
?- old_memberSFX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.
?- old_memberdSFX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.
Alright! Same results as before.
Let's dig a bit deeper! As a show-case for t_non_empty_suffix/2 consider duplicate_in/2.
Using t_non_empty_suffix/2, Prolog lambdas, (=)/3, and memberd_t/3 we define:
','(P_1, Q_1, T) :-
if_(P_1, call(Q_1,T), T = false).
duplicate_in(X, Xs) :-
t_non_empty_suffix(X+\Es^E^( X = E, memberd_t(E, Es) ), Xs).
Sample query:
?- duplicate_in(X, [1,2,3,2,3,4,3,4,5]).
X = 2 % [1,2,3,2,3,4,3,4,5] (2 occurs twice)
; X = 3 % [1,2,3,2,3,4,3,4,5] (3 occurs thrice)
; X = 4 % [1,2,3,2,3,4,3,4,5] (4 occurs twice)
; false.
memberb/2 is a typical example from constructive negation. You can turn the requirement upside down, and for example require:
?- ~ member(X, [a,b,c]).
dif(X, a),
dif(X, b),
dif(X, c)
Where ~ would be constructive negation. For a discussion on how constructive negation relates to if_ see for example here.
The disadvantage of fully declarative inductive definitions, for memberd/2 or somesuch is that the Prolog disjunction (;)/2 is not able to simplify
constraints, and that Prolog doesn't have a forall that would also simplify constraints such as diff/2.
So that in the end when you do it correctly with the limited (;)/2 and missig forall you get in the best case complete solutions that contain a lot of redundant constraints when you look at the full solution sets that the interpreter would produce.
Here is an example in Jekejeke Prolog, it requires the Minlog extension for the predicate dif/2 to be available:
:- use_module(library(term/herbrand)).
:- use_module(library(basic/lists)).
test(Y) :- dif(X, a), member(Y, [a,X]).
?- test(X).
X = a,
dif(_A, a) ;
dif(X, a)
The above two answers basically say X = a or ~(X = a) which is in most logics the same as a single answer true.
You would need a Prolog interpreter, that at some points works set oriented. And maybe some operators that would force a set oriented processing. But it might break traditional Prolog code. You can probably not just sneak in fully declarative definitions into code that was based on not so declarative definitions.
Bye

ERROR: Out of local stack in my Prolog code

I cannot figure out why the following query from the given Prolog code generates the error Out of local stack.
Prolog code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
likes(X,Z) :- likes(X,Y), likes(Y,Z).
the query
?- likes(g,X).
results in
X = c ;
X = a ;
X = b ;
ERROR: Out of local stack
Edit 1 This is the way I think that Prolog should deal with this query,
likes(g,c) is a fact, so X={c}
likes(g,b) <= likes(g,c) and likes(c,b), so X={c,b}
likes(g,a) <= likes(g,b) and likes(b,a), so X={c,b,a}
likes(g,d) <= likes(g,b) and likes(b,d), so X={c,b,a,d}
likes(g,a) and false, so nothing to add to X
likes(g,d) and false, so nothing to add to X
end of backtracking search.
Edit 2 I managed to get what I was looking for by the following modification of the code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
indirect_likes(A,B):- likes(A,B).
indirect_likes(A,C):- likes(B,C), indirect_likes(A,B).
the query
?- indirect_likes(g,Which).
results in
Which = c ;
Which = a ;
Which = b ;
Which = a ;
Which = d ;
false.
However, there is still something which I cannot figure out the rationale behind. If I change the last rule to be
indirect_likes(A,C):- indirect_likes(A,B), likes(B,C).
Then I get ERROR: Out of local stack! As far as I know, logical conjunction is commutative.
To get the transitive-closure of binary relation R_2, use meta-predicate closure/3 like so:
?- closure(R_2,From,To).
Let's run a sample query of closure/3 together with likes/2!
?- closure(likes,X,Y).
X = g, Y = c
; X = g, Y = a
; X = g, Y = b
; X = g, Y = a % redundant
; X = g, Y = d
; X = c, Y = a
; X = c, Y = b
; X = c, Y = a % redundant
; X = c, Y = d
; X = b, Y = a
; X = b, Y = d
; false. % query terminates universally
We get the same answers when we use indirect_likes/2, but in a different order:
?- indirect_likes(X,Y).
X = g, Y = c
; X = c, Y = a
; X = c, Y = b
; X = b, Y = a
; X = b, Y = d
; X = g, Y = a
; X = g, Y = b
; X = c, Y = a % redundant
; X = g, Y = a % redundant
; X = c, Y = d
; X = g, Y = d
; false. % query terminates universally
As you stated in your comments to #C.B.'s answer, binary relations are not necessarily reflexive and/or symmetric. With the definition you gave, likes/2 is neither:
?- likes(X,X).
false. % not reflexive (not even close)
?- likes(X,Y), likes(Y,X).
false. % not symmetric (not even close)
So far, so good!
Let's tentatively add the following additional fact to your database:
likes(b,b).
With this expanded definition, indirect_likes/2 behaves erratically:
?- indirect_likes(b,b).
true
; true
; true
... % does not terminate universally
?- indirect_likes(X,Y), false. % do we get finite failure?
... % no! query does not terminate universally
What can we do? Let's use meta-predicate closure/3 with the expanded version of likes/2!
?- closure(likes,b,b).
true % succeeds non-deterministically
; false. % query terminates universally
?- closure(likes,X,Y), false. % do we get finite failure?
false. % yes! query terminates universally
The bottom line?
In pure Prolog, conjunction is commutative, as far as the logical meaning is concerned.
Due to Prolog's SLD resolution, the goal false,repeat finitely fails, but repeat,false does not.
The programmer needs to take care of termination, but usually this is a small price to pay for the raw performance and control that Prolog offers.
In this answer I passed "termination worries" on to the implementor of meta-predicate closure/3 :)
You spin off into infinite recursion.
Once you get to likes(b,a), you call likes(a,_G4382), which has no fact defined so it switches to the rule likes(X,Z) :- likes(X,Y), likes(Y,Z). So it calls likes(a,_G4383) which calls likes(X,Z) :- likes(X,Y), likes(Y,Z). over and over and over.
You might want to define and auxillary predicate aux_likes/2 that hosts all your facts. This will only work if there are no circular relationships, i.e. aux_likes(b,c) and aux_likes(c,b). You would also need to define likes(X,X). This is essentially a graph problem and in graph theory a node has to be connected to itself. If you use it as a generator, it will go off into into infinite recursion (if you have cycles) unless you add cuts which are not ideal.
If using swi-prolog, feel free to enter the debug or spy query to see what's going on.
Code:
aux_likes(g,c).
aux_likes(c,a).
aux_likes(c,b).
aux_likes(b,a).
aux_likes(b,d).
likes(X,Z) :- aux_likes(X,Y), likes(Y,Z).
likes(X,X).
Output with new predicate:
?- likes(g,X),print(X),nl,fail.
a
a
d
b
c
g
false.
This says g can like a through c or through b. It likes d through b, it likes b through c and it likes c directly. It also must like itself inorder to query like this. If you would rather have the usage mode (+,+) meaning you supply it with both terms and no variables (as a checker) you can do
?- likes(g,c).
true .

swi prolog unified return elements in list

I want to return all elements in a list like the result below in X
?return_list_members([1,2,3,4,5], X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
I have the following code but it also returns the empty list element [] witch is not desirable.
return_member(X, X).
return_list_members([], []).
return_list_members([H|T], X) :- return_member(H, X); return_list_members(T, X).
output when questioned
?return_list_members([1,2,3,4,5], X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = [].
also the true or false at the end values are not desirable at the end.
The goal is to achieve a function witch outputs like the built-in function between/3 to be used in a foreach statement
Note that the procedure you are trying to write is the builtin predicate member/2.
?- member(X, [1,2,3,4,5]).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
You can also write your own definition, e.g.:
return_list_members([X|_], X).
return_list_members([_|T], X):-
return_list_members(T, X).
and if you don't want the interpreter to return 'false' at the end, you can add another clause at the beginning (as the first clause):
return_list_members([X], X):- !.
Note however that this clause will have side effects if you call this procedure with the first parameter uninstantiated.
I tried to write between_/3:
between_(X, X, X) :-
!.
between_(X, Y, X) :-
X < Y.
between_(X, Y, N) :-
X < Y,
T is X + 1,
between_(T, Y, N).
The first clause it's required to avoid the final false (as already noticed by gusbro).

Resources