How to not repeat results in prolog language - prolog

So I have this data base in my prolog program about restaurants that have a name and the people working in it and the meals it serves :
restaurant(hardees,[abo_abdo,abo_ahmad,tahseen],[grilled_chicken,jambo_beef,grilled_cheese_sandwich,roast_beef]).
restaurant(subway,[eftikar,tahseen,samer],[potato_salad,chicken_rice,jambo_beef,srevice_dish]).
restaurant(mcDonalds,[amer,zaher,maher],[service_dish,beef_stew,potato_corn,grilled_chicken,roast_beef]).
restaurant(kfc,[mufeed,mazen,izdihar,maher],[mushroom_rice,service_dish,jambo_beef]).
and I want to know if there's a meal that's present in more than one restaurant.
I have this instruction (and there should only be one parameter for this instruction) :
multi_available(X):- restaurant(Y1,_,Z1),member(X,Z1),
restaurant(Y2,_,Z2),Y1 \= Y2 ,member(X,Z2).
and it's presenting these results :
multi_available(X).
X = grilled_chicken ;
X = jambo_beef ;
X = jambo_beef ;
X = roast_beef ;
X = jambo_beef ;
X = jambo_beef ;
X = service_dish ;
X = grilled_chicken ;
X = roast_beef ;
X = service_dish ;
X = jambo_beef ;
X = jambo_beef ;
How can I have my results without the repetition.
Thanks alot

The traditional way is to use setof/3 or findall/3 and sort/2. Both however result in first computing all answers and next you have a list of answers. You can turn that again to a satisfiable goal using member/2.
SWI-Prolog offers library(solution_sequences), which provides operators that are known from SQL, such as distinct/1,2, limit/2, offset/2, etc. Using that, you simply call
?- distinct(multi_available(X)).
which ensures that variant solutions are removed, gives the first answer as it becomes available and doesn't switch between answers and lists of them so you can easily create more complex queries.

Related

How not to show if there is same result occurs more than once- Prolog

Scenario
I have the code as below. My question is how to don't show appearing same result more than once.
male(charles).
male(andrew).
male(edward).
female(ann).
age(charles, 70).
age(ann, 65).
age(andrew, 60).
age(edward, 55).
nextking(X) :- age(X,P), age(Y,Q),
P>=Q, X\==Y; age(X,55).
Current Output
What I need
I need the output to be charles, ann, andrew, edward. No repetition of names.
With a fairly recent version, you can use library(solution_sequences):
?- distinct(nextking(X)).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
or use the classic 'all solutions' builtin:
?- setof(K,K^nextking(K),Ks),member(X,Ks).
Ks = [andrew, ann, charles, edward],
X = andrew ;
Ks = [andrew, ann, charles, edward],
X = ann ;
...
but in this case, we loose the answer order defined by the KB.
Your nextking/1 predicate is rather inefficient, and furthermore does not guarantee the persons to be sorted by age.
If we would for example put charles last in the list of facts, we get:
?- nextking(X).
X = ann ;
X = ann ;
X = andrew ;
X = charles ;
X = charles ;
X = charles ;
X = edward.
basically te predicate you wrote has two clauses:
nextking(X) :-
age(X,P),
age(Y,Q),
P >= Q,
X\==Y.
nextking(X) :-
age(X, 55).
The first simply will yield any X for which there exists a person Y that is younger. But that thus gives no guarantees that these elements are sorted. Finally the last predicate will unify with all persons X that are 55 years old. For this specific case this works, but it would mean if we state another fact age(louise, 14), then this will fail. Not only is the approach incorrect, but even if it was correct it will be very "unstable".
We can make use of the setof/3 [swi-doc] predicate that does not only perform a uniqness filter, but also sorts the elements.
Since we want to sort the members of the royal family by descending age, we thus should construct 2-tuples (or an other structure that encapsulates the two parameters) where the first parameter contains the negative age, and the second parameter the corresponding person.
We can then use member/2 [swi-doc] to "unwind" the list in individual unifications:
nextking(X) :-
setof((NA, X), A^(age(X, A), NA is -A), Royals),
member((_, X), Royals).
This will produce the list of elements like:
?- nextking(X).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
regardless how the facts are ordered in the source file.

Prolog nth1 anonymous variables

I have a List with Integers and anonymous variables and I try to find the index of a special values. Problem is as soon I'm using nth1/3 to find the indices Prolog assigns values to the anonymous variables and therefore I find way too indices.
Example:
List = [1,\_,1], where I want as result X = 1, X = 3 from nth1(X,List,1), but as stated before I get X = 1, X = 2, X = 3.
There is a somewhat problematic issue hidden in your requirements: They violate an important declarative property called monotonicity. By this we mean that adding constraints can at most make the solution more specific, never more general.
For example, with the solution you posted, we get:
?- list_el_index([_], 1, N).
false.
Now I add a constraint by imposing an additional requirement on the hitherto free anonymous variable:
?- Var = 1, list_el_index([Var], 1, N).
Var = 1,
N = 0 .
I mean: Come on! We have added a constraint, and as a result get more solutions than before? Such a result is unfortunate and prevents us from reasoning in a logical way about this program.
The program also fails us in other respects. For example, let us ask: Which solutions are there at all?
?- list_el_index(Ls, El, I).
nontermination
Ideally, we would like the program to generate solutions in such cases! This generality is one of the foremost attractions of logic programming, and distinguishes it from more low-level paradigms.
One way to solve such issues is to symbolically distinguish the different kinds of elements that appear in your list.
For example, let us use:
u for an unknown value.
i(I) for an integer I.
With this new representation, your solution becomes:
list_el_index([i(I)|_], I, 0).
list_el_index([_|Tail], Element, Index) :-
list_el_index(Tail, Element, Index0),
Index #= Index0+1.
I have also taken the liberty to replace (is)/2 by (#=)/2, to advertise and stick to more general integer arithmetic that lets us more freely reorder the goals, if necessary. Depending on your Prolog implementation, you may have to import a library to benefit from (#=)/2.
With this representation, your initial case becomes:
?- list_el_index([i(1),u,i(1)], 1, Index).
Index = 0 ;
Index = 2 ;
false.
This works as desired!
Importantly, we can use the predicate also more generally, namely to generate possible answers:
?- list_el_index(Ls, El, I).
Ls = [i(El)|_2994],
I = 0 ;
Ls = [_2992, i(El)|_3000],
I = 1 ;
Ls = [_2992, _2998, i(El)|_3006],
I = 2 ;
Ls = [_2992, _2998, _3004, i(El)|_3012],
I = 3 .
Due to the program's monotonicity, we can fairly enumerate solutions by iterative deepening:
?- length(Ls, _), list_el_index(Ls, El, I).
Ls = [i(El)],
I = 0 ;
Ls = [i(El), _4812],
I = 0 ;
Ls = [_4806, i(El)],
I = 1 ;
Ls = [i(El), _4812, _4818],
I = 0 ;
etc.
This has become possible by using a representation that lets us distinguish the cases by pattern matching. Consider using this approach to make your programs usable in all directions, and to make logical reasoning applicable. It is quite easy to apply by using the appropriate wrapper or constant, and greatly increases the generality of your programs.
This works :
- L = [1,_,1], nth1(X, L, Y), ground(Y), Y= 1.
L = [1,_310914,1],
X = Y, Y = 1 ;
L = [1,_310914,1],
X = 3,
Y = 1.
Thanks to lurkers hint, I came up with this solution.
list_el_index([El1|_], El2, 0) :-
El1 == El2.
list_el_index([_|Tail], Element, Index) :-
list_el_index(Tail, Element, Index1),
Index is Index1+1.

Trying to generate list of non-zero integers in Prolog

I'm trying to define the function int(?X) in prolog which is a non-zero integer number generator which works like this:
?- int(X). X = 1 ; X = -1 ; X = 2 ; X = -2 ;
I tried the following with no luck:
int(X):- positives(Y), Y is abs(X).
positives(1).
positives(X):- positives(Y), X is Y+1.
but I'm getting the following error:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I make this work? Thanks!
There is an easy way to find and correct such problems.
Step one: Put clpfd constraints in your program. To do this, simply1 replace (is)/2 by the CLP(FD) constraint (#=)/2, i.e.:
int(X) :- positives(Y), Y #= abs(X).
positives(1).
positives(X):- positives(Y), X #= Y+1.
Step two: The query now completes without errors, and shows you what you are describing:
?- int(X).
X in -1\/1 ;
X in -2\/2 ;
X in -3\/3 ;
X in -4\/4 .
So, from the above, you see that what you are describing is not sufficient to obtain ground solutions: There is still a certain degree of freedom in your relations.
Step three: To actually fix the problem, we think about what we actually want to describe. Here is a start:
int(X) :- positives(Y), ( X #= Y ; X #= -Y).
Step four: We try it out:
?- int(X).
X = 1 ;
X = -1 ;
X = 2 ;
X = -2 ;
X = 3 ;
etc.
Seems to work OK, except for the fact that natural numbers are actually never negative. I leave fixing this discrepancy between the title of your question and the relation you are describing as an exercise for you.
TL;DR: When reasoning over integers, use your system's CLP(FD) constraints, then take it from there.
I am assuming that you have already put :- use_module(library(clpfd)). somewhere in your initial file, so that you can use CLP(FD) constraints in all your programs.

Prolog findall list of predicates

I've been searching but I can't find the right answer for my question.
The problem is:
a predicate
initial_estates([rb(1,1),rb(2,2),rb(3,5)]).
I want to use findall to get me a list of all the second term of rb's.
Like in this example [1,2,5]
Anyone can help
You can use lists:member/2 to interactively find all values of the pairs rb/2 in your list:
?- initial_estates(L),member(rb(X,Y),L).
L = [rb(1,1),rb(2,2),rb(3,5)],
X = Y = 1 ? ;
L = [rb(1,1),rb(2,2),rb(3,5)],
X = Y = 2 ? ;
L = [rb(1,1),rb(2,2),rb(3,5)],
X = 3,
Y = 5 ? ;
no
And based on that findall to get all second elements (Y) in one list (Res):
?- findall(Y,(initial_estates(L),member(rb(X,Y),L)),Res).
Res = [1,2,5]
Alternatively, you could also write a predicate, say rb_2nd/2, that describes the second argument to be the second element in the pair that is the first argument:
rb_2nd(rb(X,Y),Y).
And then use apply:maplist/3 to apply that relation to the list described by initial_estates/1:
?- initial_estates(L), maplist(rb_2nd,L,Res).
L = [rb(1,1),rb(2,2),rb(3,5)],
Res = [1,2,5]
I find the latter easier to read than the query using findall/3.

How to make a condition to end the query in prolog?

i'm new in prolog, so i have done a program which have a method to query something, but when i use it, it keeps yielding results even when it should end.
amigos(juanarjona,omarpacheco).
amigos(juanarjona,jasonancona).
amigos(juanarjona,jorgebolio).
amigos(juanarjona,gerardoadrian).
amigos(Amigo,Amigoslista):-!,amigos(Amigoslista,Amigo).
for example, when i execute
amigos(X,juanarjona).
it should give me just this answers:
X = omarpacheco ; X = jasonancona ; X = jorgebolio ; X = gerardoadrian
;
but what it really do is to repeat those answers without end like this
X = omarpacheco ; X = jasonancona ; X = jorgebolio ; X = gerardoadrian
; X = omarpacheco ; X = jasonancona ; X = jorgebolio ; X =
gerardoadrian . . . . . . . . . . . . (repeating)...........
so, that's why i'm recurring to you guys, i need to know how to establish a condition which do not let repeating the answers.
Sorry for my bad english by the way.
I Forgot to say that it must be with just one predicate in this case "amigos"
It's easy: Use two predicates instead of one!
The first predicate comprises facts only:
amigos(juanarjona, omarpacheco).
amigos(juanarjona, jasonancona).
amigos(juanarjona, jorgebolio).
amigos(juanarjona, gerardoadrian).
The second one—built on top of the first one—provides the symmetric closure1:
sym_amigos(X, Y) :- amigos(X, Y).
sym_amigos(X, Y) :- amigos(Y, X).
Sample query using SICStus Prolog 4.3.2:
| ?- sym_amigos(P, Q).
P = juanarjona, Q = omarpacheco ? ;
P = juanarjona, Q = jasonancona ? ;
P = juanarjona, Q = jorgebolio ? ;
P = juanarjona, Q = gerardoadrian ? ;
P = omarpacheco, Q = juanarjona ? ;
P = jasonancona, Q = juanarjona ? ;
P = jorgebolio, Q = juanarjona ? ;
P = gerardoadrian, Q = juanarjona ? ;
no
As your fact base gets larger and larger, looking at all the concrete answers gets tiresome... So, to check if sym_amigos/2 terminates universally, we can run a query like this one:
| ?- sym_amigos(P, Q), % looking for amigos ...
false. % ... we discard every candidate solution.
no % "no" means "terminates universally"
Above query can never yield any solution—after all, it is a conjunction with the goal false/0:
It can, however, tell us if the above goal terminates universally.
If Prolog returns no—it does2—we know that sym_amigos/2 terminates universally.
Footnote 1:
meta-predicate symm/2 covers the common idiom "symmetric closure".
Footnote 2: SWI-Prolog does not reply no but false instead.

Resources