Decision Tree in Prolog - prolog

The following is my Prolog program for a decision tree which gives output oil or telecommunication or computers (investment option for the person:oil-high risk,telecommunication- moderate risk,computer-stable risk) depending on the input given name,marital_status, income and mortgage. But I am getting an error!
moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I),
I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M),M=married,ask_income(X,I), I>50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000,
ask_age(X,A),A>50,!.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000,
ask_age(X,A),A=<50,!.
invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.
main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital
status:married or single?'), read(Y), asserta(marital_status(X,Y)).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), read(Y),
asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)),write('what is your remaining mortgage?'),
read(Z), asserta(mortgage(X,Z)).
ask_age(X,A):-not(age(X,A)).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), asserta(age(X,A)).

As SWI-Prolog is telling you, marital_status/2 is not defined. You reference it in:
ask_marital_status(X,Y) :- marital_status(X,Y).
But you never defined it anywhere.

This is what I get when I try to compile:
Warning: The predicates below are not defined. If these are defined
Warning: at runtime using assert/1, use :- dynamic Name/Arity.
Warning:
Warning: age/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:80:16: 1-st clause of ask_age/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:81:19: 2-nd clause of ask_age/2
Warning: income/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:70:19: 1-st clause of ask_income/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:71:22: 2-nd clause of ask_income/2
Warning: marital_status/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:64:4: 1-st clause of ask_marital_status/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:66:8: 2-nd clause of ask_marital_status/2
Warning: mortgage/2, which is referenced by
Warning: /home/bvassile/Documents/code/prolog/marital.pl:75:21: 1-st clause of ask_mortgage/2
Warning: /home/bvassile/Documents/code/prolog/marital.pl:76:24: 2-nd clause of ask_mortgage/2
true.
So, I follow the recommendation in the first two lines of the warning message an add the following to the top of the file:
:- dynamic age/2, income/2, marital_status/2, mortgage/2.
I also corrected the mistake in the definition of ask_age/2. With this program (with corrected formatting):
:- dynamic age/2, income/2, marital_status/2, mortgage/2.
moderate_risk(X) :-
ask_marital_status(X,Y),
Y=married,
ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z=<50000,
!.
moderate_risk(X) :-
ask_marital_status(X,M),
M=married,
ask_income(X,I), I>50000,
!.
moderate_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I=<35000,
!.
stable_risk(X) :-
ask_marital_status(X,M),
M=married,
ask_income(X,I), I=<50000,
ask_mortgage(X,Z), Z>50000,
!.
stable_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I>35000,
ask_age(X,A), A>50,
!.
high_risk(X) :-
ask_marital_status(X,M),
M=single,
ask_income(X,I), I>35000,
ask_age(X,A),A=<50,
!.
invest(X,oil) :-
stable_risk(X),
!.
invest(X,telecommunications) :-
moderate_risk(X),
!.
invest(X,computers) :-
high_risk(X),
!.
main(X,Z) :-
var(X),
write('what is your name?'), read(X),
invest(X,Z),
!.
main(X,Z) :-
invest(X,Z),
!.
ask_marital_status(X,Y) :-
marital_status(X,Y).
ask_marital_status(X,Y) :-
not(marital_status(X,Y)),
write('what is your marital status:married or single?'), read(Y),
asserta(marital_status(X,Y)).
ask_income(X,Y) :- income(X,Y).
ask_income(X,Y) :- \+ income(X,Y),
write('what is your annual income?'), read(Y),
asserta(income(X,Y)).
ask_mortgage(X,Z) :- mortgage(X,Z).
ask_mortgage(X,Z) :- \+ mortgage(X,Z),
write('what is your remaining mortgage?'), read(Z),
asserta(mortgage(X,Z)).
ask_age(X,A) :- age(X,A).
ask_age(X,A) :- \+ age(X,A),
write('what is your age?'), read(A),
asserta(age(X,A)).
You will notice that you have a silly amount of cuts. Most of them are probably unnecessary. Especially cuts at the end of clause bodies are always never meant to be there. You can try and remove all cuts at ends of clauses and see if this changes the behaviour of your program.
I can now load and run the code with ?- main(boris, Z)..

Related

Why does SWI-Prolog fail when mentioning a predicate without any facts in a rule?

Here is my Prolog program:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
:- use_module(library(tabling)).
:- table reachable/1.
reachable(X) :- start(X).
reachable(X) :- reachable(Y), link(Y, X).
start(london).
% link(london, paris).
% link(paris, london).
% link(london, frankfurt).
% link(paris, frankfurt).
% link(frankfurt, paris).
main :-
forall(reachable(X), writeln(X)),
halt.
main :-
halt(1).
Running it gives this error:
swipl links.pl
Initialization goal raised exception:
ERROR: 'reachable tabled'/1: Undefined procedure: link/2
However this works:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
:- use_module(library(tabling)).
:- table reachable/1.
reachable(X) :- start(X).
reachable(X) :- reachable(Y), link(Y, X).
start(london).
link(tokyo, hongkong).
main :-
forall(reachable(X), writeln(X)),
halt.
main :-
halt(1).
swipl links.pl
london
How can I make my program work with and without and link facts?
swipl --version
SWI-Prolog version 7.6.4 for amd64
If you intend to dynamically add the facts to the database later (for example via assertz/2 or asserta/2) you should use the directive dynamic/1:
:-dynamic link/2.
This prevents bugs in your program due to typos.

Prolog combinatoric of two lists ignoring the last items

I'm trying to get the combinatorics of two lists ignoring the last element of both.
the code:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
isady(H, L2);
ady(T, L2).
output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
stop here
a-f
b-d
b-e
stop here
b-f
stop here
c-d
c-e
stop here
c-f
expected output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
As you can see, it doesn't stop when it has to, does anyone knows why?
Try this:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
T\=[],
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
T\=[],
isady(H, L2);
ady(T, L2).
The new condition T \= [] will prevent the use of the last elements of both lists.
[EDIT] You can also explicitly use the pattern for a list of length at least 2, to avoid the execution of the "step case" clause with lists of length 1:
isady(_, [_]).
isady(E, [X,Y|T]) :-
writeln(E-X),
isady(E,[Y|T]).
ady([_], _).
ady([X,Y|T], L) :-
isady(X, L),
ady([Y|T], L).
Result:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
true ;
false.

Do not know how to say male(X) not equal to female(X)

I have the following code in prolog.
male(X).
female(X).
child(X,Y).
mother(X,Y) :- female(X), child(Y,X).
this code outputs yes even when I test it as
male(X), mother(X,Y).
I don't how should I code male(X) is not equal to female(X) in this?
I have tried mother(X,Y) :- female(X), !, +male(X), child(Y,X). But this doesn't work.

Use "univ" Prolog predicate with a Logtalk object method as parameter

How to use the 'Univ' ( =../2 ) prolog predicate with a Logtalk object method as parameter ?
Consider this code :
baz(foo(X)) :-
write(predicate), write(X), nl.
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [bar::baz, foo(testfoo2)],
write(TermLgt), nl, Term,nl.
:- object(bar).
:- public(baz/1).
baz(foo(X)) :-
write(method), write(X), nl.
:- end_object.
:- object(main).
:- public(run/0).
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [bar::baz, foo(testfoo2)],
write(TermLgt), nl, Term,nl.
:- end_object.
I'll obtain :
?- {myfile}.
% (0 warnings)
true.
?- run.
baz(foo(testfoo))
predicatetestfoo
ERROR: =../2: Type error: `atom' expected, found `bar::baz' (a compound)
?- main::run.
baz(foo(testfoo))
ERROR: Undefined procedure: baz/1
ERROR: However, there are definitions for:
ERROR: baz/1
What workaround to use for a good interpretation / compilation ? It seems issue is the same with swi-prolog building predicate like predsort/3 (predsort/3 doc).
The standard =../2 predicate expects, when constructing a term from a list, that the first list argument be an atom but bar::baz is a compound term with functor ::/2 (which is both defined as a predicate - for top-level queries - and as an operator when Logtalk is loaded). The solution is to write instead:
baz(foo(X)) :-
write(predicate), write(X), nl.
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, call(Term), nl,
TermLgt =.. [::, bar, Term],
write(TermLgt), nl, call(Term), nl.
:- object(bar).
:- public(baz/1).
baz(foo(X)) :-
write(method), write(X), nl.
:- end_object.
:- object(main).
:- public(run/0).
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [::, bar, Term],
write(TermLgt), nl, Term,nl.
:- end_object.
With this changes, you get:
?- {univ}.
% [ /Users/pmoura/Desktop/univ.lgt loaded ]
% (0 warnings)
true.
?- run.
baz(foo(testfoo))
predicatetestfoo
bar::baz(foo(testfoo))
predicatetestfoo
true.

Error in Family Tree using Prolog

I have some issues in my family tree. As required, I need to create predicates on father, mother, son, daughter, grandfather, sibling, aunt, uncle, cousin, spouse, parent_of based on the facts of Male, Female, parent_of.
male(jerry).
male(stuart).
male(warren).
male(peter).
female(kather).
female(maryalice).
female(ann).
brother(jerry,stuart).
brother(jerry,kather).
brother(peter, warren).
sister(ann, maryalice).
sister(kather,jerry).
parent_of(warren,jerry).
parent_of(maryalice,jerry).
father(X,Y) :- male(X), parent_of(X,Y).
mother(X,Y) :- female(X), parent_of(X,Y).
son(X,Y) :- male(X), parent_of(Y,X).
daughter(X,Y) :- female(X), parent_of(Y,X).
grandfather(X,Y) :- father(X,P), parent_of(P,Y).
sibling(X,Y):- parent_of(P,X), parent_of(P,Y), X\=Y.
aunt(X,Y) :- sister(X,P), parent_of(P,Y).
uncle(X,Y) :- brother(X,P), parent_of(P,Y).
cousin(X,Y):- sibling(P,Q), parent_of(P,X), parent_of(Q,Y).
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
The parent_of predicate gives me an error. Clasues of parent_of/2 are not together in the source file. When I ignore the error and run a query ?- sibling(jerry, stuart), it gives me an error out of local stack. Anyone know how to solve this problem. Your help will be appreicated. Thanks.
Problem 1
The parent_of predicate gives me an error. Clasues of parent_of/2 are not together in the source file.
Simply place definitions of the predicate right next to eachother
Change
parent_of(warren,jerry).
parent_of(maryalice,jerry).
...
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
to
parent_of(warren,jerry).
parent_of(maryalice,jerry).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
...
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
Problem 2
?- sibling(jerry, stuart), it gives me an error out of local stack.
You have a circular logic error. You define parent_of\2 in terms of father\2 and father\2 in terms of parent_of\2. This will cause each to circle off into Prolog never-never-land.

Resources