Prolog - Allowing lists L iff #L > n in setof/3 - prolog-setof

likes(russel, wittgenstein).
likes(whitehead, wittgenstein).
likes(godel, wittgenstein).
likes(hardy, ramanujan).
likes(littlewood, ramanujan).
at_least_three_fans :-
setof(X, Z^(fact(X, idol), fact(Z, idol)), admirers).
I'd like to have print only Z : Z = wittgenstein, i.e., I'd like to have only the idols that have 3 or more admirers. The output to the predicate above:
?- at_least_three_fans.
idol = wittgenstein,
admirers = [godel, russell, whitehead].
idol = ramanujan,
admirers = [littlewood, hardy].
The following occurred to me:
at_least_three([_,_|_]).
But how am I to use it?
Thank you.

Related

How to find kth generation of a family tree in Prolog?

I am trying to find a list of all the family members for the kth generation of a given family. We are given the first members of the family and the family tree as well. Below is my KB for the same and also the implementation. I am not able to figure how I can get the kth generation for this family tree? Lets say k = 4. One way of doing it is that I can find 4 times the relation like this:
4thGen(X,Y) :- parent(X,A),parent(A,B),parent(B,C),parent(C,Y)
but this is not the correct way for this I believe.
male(alex).
male(romeo).
male(oscar).
male(peter).
male(bruno).
male(georg).
male(otto).
male(pascal).
male(jean).
female(lina).
female(julia).
female(rosa).
female(eva).
female(ruth).
female(silvia).
female(ida).
female(irma).
female(olga).
female(marie).
female(tina).
parent(alex,julia).
parent(alex,rosa).
parent(lina,julia).
parent(lina,rosa).
parent(romeo,peter).
parent(julia,peter).
parent(rosa,silvia).
parent(oscar,ida).
parent(eva,ida).
parent(eva,bruno).
parent(peter,bruno).
parent(peter,georg).
parent(peter,irma).
parent(ruth,georg).
parent(ruth,irma).
parent(silvia,otto).
parent(silvia,pascal).
parent(irma,olga).
parent(irma,jean).
parent(otto,olga).
parent(otto,jean).
parent(jean,tina).
parent(marie,tina).
father(X,Y):-parent(X,Y),male(X).
grandfather(X,Y):-father(X,Z),parent(Z,Y).
In order to make more general predicates you can use recursion:
kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 is K-1,kthGen(A,Y,K1).
Here are some queries:
?- kthGen(alex,julia,1).
true ;
false.
?- kthGen(alex,peter,2).
true ;
false.
?- kthGen(alex,bruno,2).
false.
?- kthGen(alex,bruno,3).
true ;
false.
Two important things to notice here:
Firstly your graph is directed (e.g if parent(A,B) you can't have parent(B,A) ), this matters because if it was undirected you could fall into cycles (e.g kthGen(alex,julia,4). would succeed due to the path alex->julia->alex->julia ,you could solve that by adding another list that keeps track persons you've visited).
Secondly if you try:
?- kthGen(alex,bruno,K).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [8] kthGen(alex,bruno,_7630)
ERROR: [7] <user>
So the predicate kthGen/3 does not have relational behavior. You could use library CLPFD:
:- use_module(library(clpfd)).
kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 #= K-1,kthGen(A,Y,K1).
Now if you try:
?- kthGen(alex,bruno,K).
K = 3 ;
false
much better !!.
UPDATE
In order to find kth generation persons from a person X you could modify accordingly:
:- use_module(library(clpfd)).
kthGen(Y,1,[Y]).
kthGen(X,K,[X|T]) :- parent(X,A),K1 #= K-1,kthGen(A,K1,T).
Example:
?- kthGen(alex,4,L).
L = [alex, julia, peter, bruno] ;
L = [alex, julia, peter, georg] ;
L = [alex, julia, peter, irma] ;
L = [alex, rosa, silvia, otto] ;
L = [alex, rosa, silvia, pascal] ;
false.
This gives all the possible 4th generations from alex. If you want to find more complex e.g 4th gen from alex or lina you could find it separately an write another predicate that concatenates the results...
UPDATE 2
In last update I keep track of all persons until 4th generation. If you want just 4th gen simply modify like:
kthGen(Y,1,[Y]).
kthGen(X,K,L) :- parent(X,A),K1 #= K-1,kthGen(A,K1,L).
Examlpe:
?- kthGen(alex,4,L).
L = [bruno] ;
L = [georg] ;
L = [irma] ;
L = [otto] ;
L = [pascal] ;
false.
Now if you want all results in one list:
?- findall(X,kthGen(alex,4,[X]),L).
L = [bruno, georg, irma, otto, pascal].

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.

Prolog - simplify derivative

so I just got started with Prolog this semester, and got the homework to implement a pretty basic d(function, variable, derivative) which I did like this:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
I know this is not complete, but it covers all the tasks required in the exercise.
However,
?- d((x*x+2*x+3)/(3*x),x,R).
leads to
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
which doesn't look pretty at all. is/2 unfortunately doesn't like my x as it is not a number...
Is there a simple solution to achieve a cleaner result?
I would rather see this as two separate problems:
First, get derivation right (you're probably getting close, depending on your concrete requirements).
Then, work on simplifying expressions on an algebraic level. Exploit algebraic identities, see if applying the laws of commutativity / associativity / distributivity on some subexpressions enable their rewriting into something equivalent (but simpler / more compact).
As a starting point, you may want to look at the somewhat related question "Replacing parts of expression in prolog".
Here's a simplistic sketch how you could do the simplification—using iwhen/2 to safeguard against insufficient instantiation:
expr_simplified(A, B) :-
iwhen(ground(A), xpr_simplr(A,B)).
xpr_simplr(A, B) :-
( atomic(A)
-> A = B
; ( A = X+0 ; A = 0+X ; A = 1*X ; A = X*1 )
-> xpr_simplr(X, B)
; ( A = 0*_ ; A = _*0 )
-> B = 0
; A = X+X
-> B = X*2
; A = X*X
-> B = X**2
; A = X**1
-> B = X
; A =.. [F|Xs0], % defaulty catch-all
maplist(xpr_simplr, Xs0, Xs),
B =.. [F|Xs]
).
Let's see what it does with the expression you gave. We apply expr_simplified/2 until we reach a fixed point:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
expr_simplified(A,B),
expr_simplified(B,C),
expr_simplified(C,D).
A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2,
C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2,
D = C. % fixed point reached
As imperfect as the simplifier is, the expression got a lot more readable.
a possibility to get a number is to replace each instance of variable x with a value, visiting the derived tree. You should do writing a clause to match each binary operator, or use a generic visit, like
set_vars(E, Vs, Ev) :-
E =.. [F,L,R],
set_vars(L, Vs, Lv),
set_vars(R, Vs, Rv),
Ev =.. [F,Lv,Rv].
set_vars(V, Vs, N) :- memberchk(V=N, Vs).
set_vars(V, _, V).
that yields
?- d((x*x+2*x+3)/(3*x),x,R), set_vars(R,[x=5],E), T is E.
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)),
E = ((1*5+5*1+ (0*5+2*1)+0)* (3*5)- (5*5+2*5+3)* (0*5+3*1))/ (3*5* (3*5)),
T = 0.29333333333333333
but, there is a bug in your first clause, that once corrected, will allow to evaluate directly the derived expression:
d(X,V,1) :- X == V, !.
...
now, we can throw away the utility set_vars/3, so
?- d((T*T+2*T+3)/(3*T),T,R), T=8, V is R.
T = 8,
R = ((1*8+8*1+ (0*8+2*1)+0)* (3*8)- (8*8+2*8+3)* (0*8+3*1))/ (3*8* (3*8)),
V = 0.3177083333333333.

Prolog returning false for summation query

I'm new to Prolog as I'm just starting to learn and write up my own small set of database rules. Using my own .pl file of database rules, I'm having a small problem with a query that I enter in Prolog, using these rules. Below shows my small database of rules:
staff(andy,18235,3).
staff(beth,19874,4).
staff(andy,18235,5).
staff(carl,16789,2).
staff(earl,34567,9).
sum([], 0).
sum([H|T], X) :-
sum(T, X1),
X is X1 + H.
getincome(Name, Income) :-
findall(Income,staff(Name,_,Income),Member),
sum(Member, Income).
As you can see, I have written a rule that finds the total income for a particular member of staff. This works very fine, as when I input:
?- getincome(andy, X).
The program always returns:
X = 8
As it should do, however whenever I instead input:
?- getincome(andy, 8).
This always returns false, when it should be true.
However when I also input:
?- getincome(andy, 3).
This returns true, due to already being in the database.
I'm just wondering, how could I modify this rule so that this could output true for the correct summation value, entered for any given staff (most particularly Andy), as opposed to the value already in the given database?
Ignore my question above!
Thanks for the help 'false'. I'm also having another issue, this time to do with working out and displaying the sum of the income for each member. I have modified my rules, in order to display this, as follows:
getincome(Name, I) :- staff(Name, _, _ ), findall(Income,staff(Name,_,Income),Member), sum(Member, I).
Whenever I enter the query:
?- getincome(X, Y).
I keep getting duplicate results of staff (most notably Andy, of course), as show below:
X = andy,
Y = 8 ;
X = beth,
Y = 4 ;
X = andy,
Y = 8 ;
X = carl,
Y = 2 ;
X = earl,
Y = 9.
What changes can I make to avoid these duplicates?
library(aggregate) offers a clean interface to solve such kind of problems:
?- aggregate(sum(S), K^staff(E,K,S), I).
E = andy,
I = 8 ;
E = beth,
I = 4 ;
E = carl,
I = 2 ;
E = earl,
I = 9.
One way to do this is to use bagof to collect each set of incomes:
person_income(Name, Income) :-
bagof(I, X^staff(Name,X,I), Incomes), % Incomes for a given name
sumlist(Incomes, Income). % Sum the incomes
With results:
| ?- person_income(Name, Income).
Income = 8
Name = andy ? a
Income = 4
Name = beth
Income = 2
Name = carl
Income = 9
Name = earl
yes
| ?- person_income(andy, Income).
Income = 8
yes
| ?- person_income(Name, 8).
Name = andy ? a
no
| ?-
I named this person_income to emphasize that it's a relation between a person and their income, rather than getincome which is more of an imperative notion, and doesn't really reflect that you can do more with the relation than just "get the income". Also, I'm using SWI Prolog's sumlist/2 here. GNU Prolog has sum_list/2. And as #CappeliC indicates in his answer, SWI Prolog has a handy aggregate predicate for operations like this.

Cryptogram solver in Prolog

I have to solve a cryptogram which looks like this:
ABC / DEF = 0.GHGHGH...
where length of variables may be different. Also repetition may be different (like 0.XYZXYZ...). I've written a piece of code which I thought will work but it doesn't:
cryp(A,B,C) :-
mn(A, X),
mn(B, Y),
mn(C, Z),
Z = X/Y.
mn([], 0).
mn([H|T], W) :- D is 10, mn(T, W1), length(T, D), P is 10^D, W is W1 + H*P.
I execute it as crypt([A,B,C], [D,E,F], [G,H]). I thought it will at least solve ABC / DEF = GH just to have any part of working solution but it doesn't work.
I don't have any clue how to do it even for one example input. I don't know how to represent 0.GHGHGH....
EDIT:
mn/2 is for converting list of digits to number ([1,2,3] -> 123).
Here is clp(fd)-way
?- use_module(library(clpfd)).
true.
?- Vars=[A,B,C,D,E,F,G,H], Vars ins 0..9, A#\=0, D#\=0, ((10*A + B)*10+C)*99 #= ((10*D+E)*10+F)*(10*G+H),all_distinct(Vars),forall(label(Vars),format('~w~n',[Vars])).
[1,0,8,2,9,7,3,6]
[1,0,8,3,9,6,2,7]
[1,3,0,2,8,6,4,5]
[1,3,0,4,9,5,2,6]
[1,3,8,2,9,7,4,6]
[1,3,8,5,0,6,2,7]
[1,6,0,4,9,5,3,2]
[1,8,0,3,9,6,4,5]
[1,8,0,4,9,5,3,6]
[2,0,4,3,9,6,5,1]
[2,5,9,4,0,7,6,3]
[2,8,4,3,9,6,7,1]
[2,8,7,4,5,1,6,3]
[2,8,7,6,9,3,4,1]
[2,9,0,6,3,8,4,5]
[3,1,0,4,9,5,6,2]
[3,1,0,6,8,2,4,5]
[3,6,0,4,9,5,7,2]
[3,6,0,7,9,2,4,5]
[3,8,0,4,9,5,7,6]
[4,0,8,5,6,1,7,2]
[4,0,8,7,9,2,5,1]
[4,9,3,5,6,1,8,7]
[5,0,4,6,9,3,7,2]
[5,0,4,7,9,2,6,3]
[5,1,8,6,9,3,7,4]
[5,7,4,6,9,3,8,2]
[5,7,4,9,0,2,6,3]
[5,9,4,7,2,6,8,1]
[6,8,0,9,3,5,7,2]
[7,5,6,9,2,4,8,1]
You might do the following identifications: let a=0.GHGHGHGH.... Then
a = 0.GHGH....
GH + a = GH.GHGHGHGH.... = 100 a
GH = 99 a
=> a = GH/99
So you can replace it by GH/99 in your formulas.
Similarly 0.XYZXYZXYZ = XYZ/999.

Resources