Define a connectivity graph in Prolog - prolog

I'm continuing some researches in lattices and semilattices and suddenly having this question.
Basically, we have a RelationList of [a,b] pairs, which means that (a,b) is an edge. Now we should know, is a graph formed by this RelationList 1-connectivity or not.
By the way, we have an ordered graph, so order of (a,b) is important.
clear_link(X, Y, RelationList) :-
(member([X,Y], RelationList)
;
member([Y,X], RelationList)),
X =\= Y.
linked(X, Y, RelationList) :-
clear_link(X, Y, RelationList),
!.
linked(X, Y, RelationList) :-
clear_link(X, Z, RelationList),
linked(Z, Y, RelationList).
simple_connect(RelationList, E) :-
forall((member(X, E),
member(Y, E), X < Y),
linked(X, Y, RelationList)).
But, for 6-element graph I have stackoverflow.
?- simple_connect([[2,1],[2,3],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
ERROR: Out of local stack
Am I defining it wrong?

I've correct some. Now it's fine
clear_link(X, Y, RelationList) :-
member([X,Y], RelationList),
X =\= Y.
linked(X, Y, RelationList) :-
clear_link(X, Y, RelationList),
!.
linked(X, Y, RelationList) :-
clear_link(X, Z, RelationList),
linked(Z, Y, RelationList),
!.
simple_connect(RelationList, E) :-
forall((member(X, E),
member(Y, E), X < Y),
linked(X, Y, RelationList)).
connective_graph(RelationList, E) :-
findall(Relation, (
member(X, RelationList),
sort(X, Relation)
),SortRelationList),
simple_connect(SortRelationList, E).
And
?- connective_graph([[2,1],[2,3],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
true.
?- connective_graph([[2,1],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
false.
Right answer (copy to post)
connected(X, Y, RelationList) :-
(member([X,Y], RelationList);
member([Y,X], RelationList)).
path(X, Y, RelationList, Path) :-
travel(X, Y, RelationList, [X], ReversePath),
reverse(ReversePath, Path),!.
travel(X, Y, RelationList, Point, [Y | Point]) :-
connected(X, Y, RelationList).
travel(X, Y, RelationList, Visited, Path) :-
connected(X, Z, RelationList),
Z =\= Y,
\+member(Z, Visited),
travel(Z, Y, RelationList, [Z|Visited], Path).
connective_graph(RelationList, E) :-
forall((member(X, E),
member(Y, E),
X < Y)
,path(X,Y,RelationList,_)).

Related

Prolog cousin once removed and half sister/brother rules

Am working on a prolog genealogy project and cannot figure out how to make the rules for cousin once removed and half sister/brother rules. Below is what I have and cannot get it to work. Any help or suggestions would be appreciated. I have placed in bold what I have tried. I'm sure its something simple in the way I'm trying to code it.I just cannot figure it out.
person(marc,male).
person(faith,female).
person(alan,male).
person(kim,female).
person(missy,female).
person(eric,male).
person(charles,male).
person(eleanor,female).
person(roland,male).
person(corey,male).
person(amy,female).
person(tyler,male).
person(matty,male).
person(kaydi,female).
person(jenna,female).
person(allison,female).
person(emma,female).
person(hayley,female).
person(jaylin,female).
person(lukus,male).
person(brendon,male).
person(bradley,male).
person(tylerh,male).
person(dayna,female).
person(victor,male).
person(jacoby,male).
person(javi,male).
person(jordan,male).
person(jaxson,male).
person(kenzie,female).
person(richard,male).
person(reggie,male).
person(reggiejr,male).
person(beverly,female).
person(floyd,male).
person(marjorie,female).
person(kevin,male).
parent(marc,alan).
parent(faith,alan).
parent(charles,marc).
parent(charles,kim).
parent(charles,missy).
parent(charles,eric).
parent(eleanor,marc).
parent(eleanor,kim).
parent(eleanor,missy).
parent(eleanor,eric).
parent(eric,matty).
parent(eric,tyler).
parent(eric,kaydi).
parent(amy,matty).
parent(amy,tyler).
parent(amy,kaydi).
parent(missy,jordan).
parent(missy,jaxson).
parent(missy,kenzie).
parent(richard,jordan).
parent(corey,kenzie).
parent(corey,jaxson).
parent(kim,allison).
parent(kim,jenna).
parent(kim,emma).
parent(kim,jaylin).
parent(kim,hayley).
parent(kim,dayna).
parent(roland,allison).
parent(roland,jenna).
parent(roland,emma).
parent(roland,jaylin).
parent(roland,hayley).
parent(roland,dayna).
parent(dayna,javi).
parent(dayna,jacoby).
parent(victor,javi).
parent(victor,jacoby).
parent(jenna,bradley).
parent(brendon,bradley).
parent(tylerh,lukus).
parent(allison,lukus).
parent(reggie,reggiejr).
parent(beverly,reggiejr).
parent(floyd,beverly).
parent(marjorie,beverly).
parent(reggiejr,kevin).
parent(floyd,eleanor).
parent(marjorie,eleanor).
married(marc,faith).
married(charles,eleanor).
married(kim,roland).
married(eric,amy).
married(missy,corey).
married(dayna,victor).
married(allison,tylerh).
married(marjorie,floyd).
married(beverly,reggie).
father(X, Y) :- parent(X, Y), person(X,male).
mother(X, Y) :- parent(X, Y), person(female,Y).
son(X, Y) :- parent(Y,X), person(X,male).
daughter(X, Y) :- parent(X,Y), person(Y,female).
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
grandfather(X, Z) :- grandparent(X, Z), person(X,male).
grandmother(X, Z) :- grandparent(X, Z), person(female,Y).
grandson(X, Z) :- grandchild(X, Z), person(X,male).
granddaughter(Y, Z) :- grandchild(Y, Z), person(Y,female).
grandchild(X, Z) :- grandparent(Z, X).
sibling(X,Y) :- parent(Z,X), parent(Z,Y).
brother(Y, X) :- sibling(Y,X), person(X,male), not(X=Y).
sister(X, Y) :- sibling(X, Y), person(Y,female).
auntoruncle(X, W) :- sibling(X, Y), parent(Y, W).
auntoruncle(X, Z) :- married(X,Y), sibling(Y,W), parent(W,Z).
uncle(X, W) :- auntoruncle(X, W), person(X,male).
aunt(X, W) :- auntoruncle(X, W), person(female,Y).
cousin(X, Y) :- parent(Z, X), auntoruncle(Z, Y), Y\=X.
nieceornephew(X, Y) :- parent(Z, X), sibling(Z, Y).
nephew(X, Y) :- nieceornephew(X, Y), person(X,male).
niece(X, Y) :- nieceornephew(Y, X), person(Y,female).
greatgrandparent(X, Z) :- parent(X, Y), grandparent(Y, Z).
greatgrandfather(X, Z) :- greatgrandparent(X, Z), person(X,male).
greatgrandmother(X, Z) :- greatgrandparent(X, Z), person(female,Y).
greatgrandchild(X, Z) :- child(X, Y), grandchild(X, Z).
greatgrandson(X, Z) :- greatgrandchild(X, Z), person(X,male).
greatgranddaughter(X, Z) :- greatgrandchild(X, Z), person(female,Y).
married_to(X,Y) :- married(X,Y), not divorced(X,Y).
whatgender(X,Y) :- person(X,Y).
**child(X, Y) :- parent(Y, X).
cousinonceremoved(X, Y) :- cousin(Z, Y), child(X, Z).
halfsibling(X,Y) :- parent(Z,X), parent(Z,Y), parent(P,X), \+parent(P,Y).
halfbrother(X,Y) :- halfsibling(X,Y), male(X).
halfsister(X,Y) :- halfsibling(X,Y), female(X).**
strong text

Why doesn't it unify? Prolog issue

I'm trying to do a predicate in prolog which substitute the value I give to the variables of the polynomial and then it calculate the result. Here is my code:
as_monomial(X, m(X, 0, [])) :- number(X), !.
as_monomial(^(Y, Z), m(1, Z, [v(Z, Y)])) :- !.
as_monomial(*(X, ^(Y, Z)), m(G, K, Q)) :- as_monomial(X, m(G, TD, Vars)), K is (TD + Z), compress_monomial([v(Z, Y)| Vars], A), ordina_m(A, Q), !.
as_monomial(*(X, Y), m(G, K, Q)) :- as_monomial(X, m(G, TD, Vars)), K is (TD + 1), compress_monomial([v(1, Y)| Vars], A), ordina_m(A, Q), !.
as_monomial(-(X), m(-A, Y, L)) :- as_monomial(X, m(A, Y, L)).
as_monomial(X, m(1, 1, [v(1, X)])).
ordina_m(List, Sorted) :- sort(2, #=<, List, Sorted).
ordina_var(List, Sorted) :- sort(0, #=<, List, Sorted).
compress_monomial([], []) :- !.
compress_monomial([X| Xs], A2) :- compress_monomial(Xs, A), compress_monomial2(X, A, A2), !.
is_monomial(m(_C, TD, VPs)) :- integer(TD), TD >= 0, is_list(VPs).
is_polynomial(poly(M)) :- is_list(M), foreach(member(Monomio, M), is_monomial(Monomio)).
variables(Poly1, Result) :- is_polynomial(Poly1), variabili(Poly1, Result), !.
variables(Poly1, Result) :- as_polynomial(Poly1, Result1), variabili(Result1, Result), !.
variabili(poly([]), []) :- !.
variabili(poly([m(_, _, [])| Xs]), Ys) :- variabili(poly(Xs), Ys), !.
variabili(poly([m(X, Y, [v(_, A)| Vs])| Xs]), Z) :- variabili(poly([m(X, Y, Vs)| Xs]), Ys), ordina_var([A| Ys], R), compressV(R, Z), !.
compressV([], []).
compressV([X|T],[X|T1]):- member(X,T),!,canc(X,T,R), compressV(R,T1).
compressV([X|T],[X|T1]) :- compressV(T,T1).
canc(_L, [], []).
canc(L, [L|S], Z) :- canc(L, S, Z).
canc(L, [H|S], [H|Z]):- canc(L, S, Z), !.
as_polynomial(+(X, Y), poly(C)) :- as_monomial(Y, G), as_polynomial(X, poly(Gs)), compress_polynomial([G| Gs], C), !.
as_polynomial(-(X, Y), poly(C)) :- as_monomial(-Y, G), as_polynomial(X, poly(Gs)), compress_polynomial([G| Gs], C), !.
as_polynomial(X, poly([X])) :- is_monomial(X), !.
as_polynomial(X, poly([Q])) :- as_monomial(X, Q), !.
compress_polynomial([], []) :- !.
compress_polynomial([X| Xs], A2) :- compress_polynomial(Xs, A), compress_polynomial2(X, A, A2), !.
compress_polynomial2(m(X, Y, Z), [], [m(X, Y, Z)]) :- !.
compress_polynomial2(m(X, Y, Z), [m(X1, Y, Z)| Xs], [m(X2, Y, Z)| Xs]) :- X2 is (X + X1), !.
compress_polynomial2(X, [Y| Ys], [Y| Z]) :- compress_polynomial2(X, Ys, Z), !.
polyval(Poly1, V, Result) :- is_polynomial(Poly1), variables(Poly1, Vars), poly_val(Poly1, Vars, V, Result), !.
polyval(Poly1, V, Result) :- as_polynomial(Poly1, P1), variables(P1, Vars), poly_val(P1, Vars, V, Result), !.
poly_val(poly([]), , , poly([])) :- !.
poly_val(poly([m(X, Y, Z)| Xs]), Vars, V, poly([R| Ys])) :- poly_val(poly(Xs), Vars, V, poly(Ys)), print(m(X, Y, Z)), mon_val(m(X, Y, Z), Vars, V, R), !.
mon_val(m(X, Y, []), [_], [_], m(X, Y, [])) :- !.
mon_val(m(X, Y, [v(W, Z)| Vs]), [Z| Vs2], [Val| Vvs], m(X2, Y2, Z2)) :- integer(Val), mon_val(m(X, Y, Vs), Vs2, Vvs, m(X3, Y2, Z2)), X2 is (X3 * (Val ^ W)), !.
mon_val(m(X, Y, [v(W, Z)| Vs]), [_| Vs2], [_| Vvs], m(X, Y2, Z2)) :- mon_val(m(X, Y, [v(W, Z)| Vs]), Vs2, Vvs, m(X, Y3, Z2)), Y2 is (Y3 + W), !.
I hope I put all the code you need to prove it, in case please say it to me and I apologise for it. I know about the cut but, at the moment, it is just a trial. My problem is in mon_val because it looks like doesn't want to unify. An example of query I use is polyval(x+x+y, [1, 3], Q). where the output is "false" and it should return poly(m(1, 0, []), m(1, 0, []), m(3, 0, [])). Are you able to help me doing that? I just want to solve the problem and later I will also implement the sum between the numbers which is pretty easy with the rest of the code I have. Thanks guys
If you wanna know, at the end I solve the problem myself (which is, according some of you, the best way to learn and I'm agree). So my poly-val becomes:
polyval(Poly1, V, Result) :- is_polynomial(Poly1), variables(Poly1, Vars), poly_val(Poly1, Vars, V, Result), !.
polyval(Poly1, V, Result) :- as_polynomial(Poly1, P1), variables(P1, Vars), poly_val(P1, Vars, V, Result), !.
poly_val(poly([]), _, _, poly([])) :- !.
poly_val(poly([X| Xs]), Vars, V, poly(Z)) :- poly_val(poly(Xs), Vars, V, poly(Ys)), mon_val(X, Vars, V, R), compress_polynomial([R| Ys], Z), !.
/* mon_val(Monomio, Variabili, ValoreVariabili, Result) */
mon_val(m(X, _, []), [_], [_], m(X,0, [])) :- !.
mon_val(m(X, _, Z), [], [], m(X,0, Z)) :- !.
mon_val(m(X, Y, [v(W, Z) | R]), [Z| Vs], [Val|Vvs], m(X2, Y2, Z2)) :- integer(Val), mon_val(m(X, Y, R), Vs, Vvs, m(X3, Y2, Z2)), X2 is (X3 * (Val ^ W)), !.
mon_val(m(X, Y, Z), [_|Vs2], [_| Vvs], m(X2, Y2, A)) :- mon_val(m(X, Y, Z), Vs2, Vvs, m(X2, Y2, A)), !.`

Arguments aren't sufficient instantiated

I read my code for an hour but I'm not able to understand where the problem is. I read that this error means that I use an argument I didn't instantiate before but I can't see where it is. Can you help me?
as_monomial(X, m(X, 0, [])) :- number(X), !.
as_monomial(^(Y, Z), m(1, Z, [v(Z, Y)])) :- !.
as_monomial(*(X, ^(Y, Z)), m(G, K, Q)) :- as_monomial(X, m(G, TD, Vars)), K is (TD + Z), ordina_m([v(Z, Y)| Vars], Q), !.
as_monomial(*(X, Y), m(G, K, Q)) :- as_monomial(X, m(G, TD, Vars)), K is (TD + 1), ordina_m([v(1, Y)| Vars], Q), !.
as_monomial(-(X), m(-A, Y, L)) :- as_monomial(X, m(A, Y, L)).
as_monomial(X, m(1, 1, [v(1, X)])).
ordina_m(List, Sorted) :- sort(2, #=<, List, Sorted).
ordina_poly1(List, Sorted) :- sort(2, #>=, List, Sorted).
ordina_poly2(List, Sorted) :- sort(3, #=<, List, Sorted).
is_monomial(m(_C, TD, VPs)) :- integer(TD), TD >= 0, is_list(VPs).
is_polynomial(poly(M)) :- is_list(M), foreach(member(Monomio, M), is_monomial(Monomio)).
as_polynomial(+(X, Y), poly(C)) :- as_monomial(Y, G), as_polynomial(X, poly(Gs)), inverti(G, H), inverti2(Gs, Hs), ordina_poly2([H| Hs], D), inverti2(D, F), ordina_poly1(F, C), !.
as_polynomial(-(X, Y), poly(C)) :- as_monomial(-Y, G), as_polynomial(X, poly(Gs)), inverti(G, H), inverti2(Gs, Hs), ordina_poly2([H| Hs], D), inverti2(D, F), ordina_poly1(F, C), !.
as_polynomial(X, poly([X])) :- is_monomial(X), !.
as_polynomial(X, poly([Q])) :- as_monomial(X, Q), !.
/* grado massimo */
maxdegree(Poly1, Result) :- is_polynomial(Poly1), max_degree(Poly1, Result), !.
maxdegree(Poly1, Result) :- as_polynomial(Poly1, Result1), max_degree(Result1, Result), !.
max_degree(poly([]), 0) :- !.
max_degree(poly([m(_, X, _)|Xs]), X) :- max_degree(poly(Xs), Ys), X > Ys, !.
max_degree(poly([m(_, X, _)|Xs]), Ys) :- max_degree(poly(Xs), Ys), X =< Ys, !.
/* grado minimo */
mindegree(Poly1, Result) :- is_polynomial(Poly1), min_degree(Poly1, Result), !.
mindegree(Poly1, Result) :- as_polynomial(Poly1, Result1), min_degree(Result1, Result), !.
min_degree(poly([m(_, X, _)]), X) :- !.
min_degree(poly([m(_, X, _)|Xs]), X) :- min_degree(poly(Xs), Ys), X < Ys, !.
min_degree(poly([m(_, X, _)|Xs]), Ys) :- min_degree(poly(Xs), Ys), X >= Ys, !.
inverti(m(_, _, []), m(_, _, [])) :- !.
inverti(m(X, Y, [v(W, Z)| Xs]), m(X, Y, [v(Z, W)| Ys])) :- inverti(m(X, Y, Xs), m(X, Y, Ys)), !.
inverti2([], []) :- !.
inverti2([m(X, Y, [])| Zs], [m(X, Y, [])| Ss]) :- inverti2(Zs, Ss), !.
inverti2([m(X, Y, [v(W, Z)| Xs])| Zs], [m(X, Y, [v(Z, W)| Ys])| Ss]) :- inverti2([m(X, Y, Xs)| Zs], [m(X, Y, Ys)| Ss]), !.
I will not include code for as/is_polynomial cuz I already use it before and I don't have problem with that piece of code. Can you help me please?
An example for it, I tried, is maxdegree(x^5+y^500+4, R). (same thing for mindegree)
I solve my problem adding a clausure in both maxdegree and mindegree as base case:
max_degree(poly([m(_, _X, [])]), 0) :- !.
max_degree(poly([m(_, X, _)]), X).
min_degree(poly([m(_, _X, [])]), 0) :- !.
min_degree(poly([m(_, X, _)]), X) :- !.

Implement a predicate subtraction

So far, my program can add two numbers together.
s(0) represents 1, s(s(0)) represents 2 and so on
p(0) represents -1, p(p(0)) is -2 etc.
I want to be able to call a program such that
add2(s(s(0)), p(0), Z).
returns
Z = s(0).
My code is as follows:
numeral(0).
numeral(s(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
numeral(X+Y) :- numeral(X), numeral(Y).
add2(X,Y,Z):-add(X,Y,Z).
add2(X+Y, Z,A) :-add(X,Y,R),add2(R,Z,A).
add2(Z,X+Y,A) :-add(X,Y,R),add2(Z,R,A).
numeral(p(X)) :- numeral(X).
add2(p(X),Y,p(Z)) :- add2(X,Y,Z).
p(s(X)) =:= 0.
s(p(X)) =:= 0.
My logic was that if p(s(0)) was in the list, it would just equate it to 0.. I was wrong, however. Does anybody know where to go with this?
Each numeral could be represented only in one of these 3 ways:
0 - null;
s(X) - next, where X is numeral;
p(X) - previous, where X is numeral;
add2/3 should take 2 numerals and return sum of them. It could be defined manually for each possible arguments:
add2(0, 0, 0).
add2(0, s(X), Y) :- Y = s(X).
add2(0, p(X), Y) :- Y = p(X).
add2(s(X), 0, Y) :- Y = s(X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), 0, Y) :- Y = p(X).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).
Works well:
?- add2(s(s(0)), p(0), Z).
Z = s(0) .
It is notable that many cases of add2/3 rule is actually overlapped and could be eliminated:
add2(0, X, X).
add2(X, 0, X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).

Prolog and ancestor relationship

I have to write a small prolog program which checks if a given person is a ancestor of a second one.
These are the facts and rules:
mother(tim, anna).
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
The test if a person is an ancestor of another person is easy:
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
But now I have to write a method ancestor(X,Y,Z) which also prints out the relationship between two persons. It should look like this
?- ancestor(ephraim, tim, X).
false.
?- ancestor(tim, ephraim, X).
X = father(mother(tim)).
And that is the problem: I have no clue how do to this.
You can use an accumulator to adapt #Scott Hunter's solution :
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
ancestor(X, Y, Z) :- ancestor(X, Y, X, Z).
ancestor(X, Y, Acc, father(Acc)) :- father(X, Y).
ancestor(X, Y, Acc, mother(Acc)) :- mother(X, Y).
ancestor(X, Y, Acc, Result) :-
father(X, Z),
ancestor(Z, Y, father(Acc), Result).
ancestor(X, Y, Acc, Result) :-
mother(X, Z),
ancestor(Z, Y, mother(Acc), Result).
edit : as Scott Hunter showed in his edit, there's no need for an explicit accumulator here, since we can left the inner part of the term unbound easily at each iteration. His solution is therefore better !
A term manipulation alternative to the accumulator tecnique by #Mog:
parent(X, Y, mother(X)) :- mother(X, Y).
parent(X, Y, father(X)) :- father(X, Y).
ancestor(X, Y, R) :-
parent(X, Y, R).
ancestor(X, Y, R) :-
parent(X, Z, P),
ancestor(Z, Y, A),
eldest(A, P, R).
eldest(A, P, R) :-
A =.. [Af, Aa],
( atom(Aa)
-> T = P
; eldest(Aa, P, T)
),
R =.. [Af, T].
To test, I made tim a father: father(ugo, tim).
?- ancestor(tim, ephraim, X).
X = father(mother(tim)) .
?- ancestor(ugo, ephraim, X).
X = father(mother(father(ugo))) .
Simply add a term which tracts what kind of parent is used at each step (edited to get result in proper order):
ancestor(X,Y,father(X)) :- father(X,Y).
ancestor(X,Y,mother(X)) :- mother(X,Y).
ancestor(X,Y,father(Z2)) :- father(Z,Y), ancestor(X,Z,Z2).
ancestor(X,Y,mother(Z2)) :- mother(Z,Y), ancestor(X,Z,Z2).

Resources