Prolog: Difference relation between two objects - prolog

I will be honest and preface this by saying it is homework, but I desperately need help.
I am new to Prolog, coming from C++ and Javascript and no matter how hard I try, I'm just not getting it.
What I am supposed to do is to be able to find the difference between two dates (assuming non leap year).
Basically I have a knowledge base with information laid out like:
object(A, B).
object(A, B).
...
where A represents month and B represents total days of the month.
(eg. object(1, 31).)
The expression I am supposed to use for input is this:
Difference(Object(A,B), object(A,B), N).
(N = difference between the objects).
I have tried a few different things (and I know this isn't on the right track) and haven't been able to get further then:
difference(object(A,B), object(A,B),N):-
days(M,D), days(M,D),
Y = 365-D,
N is Y.
I don't understand how to make the two objects register as individual things that I can manipulate and therefore continue with the problem.
Can someone please please please point me in the right direction?
Thanks
Homework Question (AS REQUESTED).
Assume the presence of the days relation that describes how many days are in
each calendar month of a non-leap year.
days(1,31).
days(2,28).
(and so on).
The structure dateObject(M, D) describes a date. For example dateObject(6,5) would denote the 5th of June.
Write the relation difference(From, To, N), where N is the number of days between starting
date From and finishing date To. The From date is not included in the count. For
example:
?- difference(dateobject(2,1),dateobject(2,2),N).
N = 1.
If the day or month values in a date are invalid (e.g. dateobject(4,31), dateobject(13,1) then the
value of N returned should be -1. If the From date is later than To then the -1 error value should also be returned for N.

Here's a really bad solution - I'm sure someone smarter than me will come up with something better.
?- difference(dateobject(1,28),dateobject(6,1),N),write(N),nl.
days(1,31).
days(2,28).
days(3,31).
days(4,30).
days(5,31).
days(6,30).
days(7,31).
days(8,31).
days(9,30).
days(10,31).
days(11,30).
days(12,31).
daysbetween(M,FD,M,TD,N) :- !, N is TD - FD.
daysbetween(FM,FD,TM,TD,N) :-
days(FM,D),
FM2 is FM + 1,
daysbetween(FM2,FD,TM,TD,N2),
N is D + N2.
difference(dateobject(FM,FD),dateobject(TM,TD),N) :-
TM >= FM,
FD >= 1,
days(FM,FDM),
FD =< FDM,
TD >= 1,
days(TM,TDM),
TD =< TDM,
daysbetween(FM,FD,TM,TD,N),
N > 0,
!.
difference(_,_,-1).

Related

Check if a country reaches the threshold

Hi guys i'm new to prolog and i'm trying to understand something:
I have this database:
countries([belgium, france, germany, italy, luxembourg, netherlands]).
weight(france, 4).
weight(germany, 4).
weight(italy, 4).
weight(belgium, 2).
weight(netherlands, 2).
weight(luxembourg, 1).
threshold(12).
And I made this program to see if a list of countries have enough votes to get over the threshold and i want to use a predicate winning/1
winning([H|T]):-
weight(H, N1),
winning(T),
weight(T, N2),
N is N1 + N2,
N>=X,
threshold(X).
The program runs perfectly up untill the point it has to add up the voting power and conclude whether the votes reach the threshold.
Its difficult because I only want to use a predicate winning/1 can anyone help me out?
The reason it is not adding up N1 and N2 into N is because you are asking the weight-number for the entire Tail, when you should just get the weight of only the head of the Tail. Which at this point you don't have yet.
You want to create a separate (recursive) rule, winning/2 and call it from winning/1:
winning(Countries) :-
winning2(Countries,0).
In this separate winning/2 you call for the weight which you store in N and call back winning/2 recursively until N reaches the threshold.
winning2([],N) :-
threshold(X),
N >= X.
winning2([Country|Tail], N) :-
weight(Country,X),
NewN is X + N,
winning2(Tail, NewN).

Length of a list

I am a beginner to ProLog and I am attempting the following question:
Write a predicate len to calculate the total duration of a list of x
tasks, e.g.
?- len([d, j, l, n], Time).
Time = 15
There are a set of rules which need to be followed :
duration(a,5).
duration(b,7).
duration(c,3).
duration(d,4).
duration(e,10).
duration(f,4).
I have tried the following, but there is an error message and I cannot see what I am doing wrong.
length([], 0).
length([X], duration(X, T), Time).
sum([],0).
sum([X|L],N) :-
sum(L,N1),N is N1 + X.
length([X|Xs], sum([duration(Xs, Ts)], Time).
This is the error: Singleton variables: [T,Time]
Syntax error: Operator expected
I want to be able to calculate the duration of several tasks in one go by inputting the tasks as a list.
I have defined the sum. What else needs to be done ?
Can anyone help me ?
You seem to try to define length as
length([], 0).
but length is already defined predicate which bounds the second argument to the length of list.
You have to define len here.
This is not good.
length([X], duration(X, T), Time).
The following will be better.
len([X], Time) :- duration(X, Time).
But if you define len([X|Xs], Time) correctly, len([X], Time) becomes unnecessary.
I think sum is not necessary. Good luck.

combining all possible results in one list in prolog

I'm trying to find the available slot which comes from the predicate quizslots/3 quizslot(Group, Day, Slot).
quizslot(group4, tuesday, 1).
quizslot(group4, thursday, 1).
quizslot(group6, saturday, 5).
This is my hypothesis but it doesn't seem to work fine.
available_timings(G,L):-
setof(X,quizslot(G,X,_),L).
I want the result for (group4,L), L = [tuesday,1,thursday,1].
Syntax of setof:
% Set of every FooResult
?- setof(FooResult,foo(X,Y,FooResult),Result).
[FooResult1, FooResult2, ..]
% Set of tuples of every input X and FooResult
?- setof((X,FooResult),foo(X,Y,FooResult),Result).
[(X1,FooResult1), (X2,FooResult2), ..]
% Set of lists of every input X and FooResult, ommitting input Y
?- setof([X,FooResult],foo(X,_,FooResult),Result).
[[X1,FooResult1], [X2,FooResult2], ..]
I think you get the point. As lurker stated in his answer above, you are trying to have the slot included in the result, however, you tell prolog to find all distinct quizslot-facts of the form:
quizslot(group G, day X, whatever slot)
Since this wildcard will match with any slot, you cannot retrieve the actual variable holding the slot, Prolog didn't bother retrieving the variable for you.
A correct usage would be, for example, one of the following
setof([Day,Slot], quizslot(Group,Day,Slot), Result) % List of lists
setof((Day,Slot), quizslot(Group,Day,Slot), Result) % List of tuples

Selecting parts of a number and checking lists in Prolog

I have made this knowledge base from information provided in the question:
student(jill,12071992,computer_science,[tennis,lacrosse]).
student(joe,14021993,mathematics,[tennis,rugby,football]).
Which represents, the students name, their birth date, their subject, and the sports they play.
Question 1 -
born_before(N,Y) - student named N was born before year Y
born_before(N,Y):-student(N,____X,_,_), Y > X.
obviously the above doesn't work, my problem is i don't know how to segregate the YYYY from DDMMYYYY term in prolog, to then set it to X, so it can be compared to the Y value.
Question 2 -
plays_sport(N,S) - student named N plays sport S.
my attempt
plays_sport(N,S):-student(N,_,_,[S|Sx]), plays_sport(N,Sx).
this always returns false. I have tried to use tail recursion so that the sport can be matched from the lists of sports in the knowledge base.
For the first part of your question you could write rules to extract the year, the month, and the day from an integer representing the date in the ddmmyyyy format, like this:
extract_year(DDMMYYYY, YYYY) :- YYYY is mod(DDMMYYYY, 10000).
extract_day(DDMMYYYY, DD) :- DD is DDMMYYYY // 1000000.
extract_month(DDMMMYYYY, MM) :- DDMM is DDMMMYYYY // 10000, MM is mod(DDMM, 100).
// operator represents integer division, when the fractional part is dropped from the answer. mod/3 is an operation for finding the remainder of integer division.
You could then combine them back into yyyymmdd format, and compare as integers (demo).
For your second part, you could use memberchk(Element, List) to check if the desired sport is present in the list:
plays_sport(N,S) :- student(N,_,_,AllSports), memberchk(S, AllSports).

How to compare time to a time range specified in Prolog?

Let's say i have a structure comparetime(hours,mins),
when a user keys example comparetime(10,40) ,
the structure will make comparison on a time range specified example
timing entered
1) from 10:00 to 12:00 will print a message and
2) from 18:00 to 20:00 will print a message .
if the time keyed is not inside the range, it will also print a message.
how can I do this ?
it's easy to compare words but i'm really having a tough time with comparing time.
It's easy compare words?
You should try it when internationalization is involved to appreciate how difficult could be!
Far easier is compare pair of integers, as from your problem (if I understand the question).
message_on_range(1, 10:00, 12:00, 'it\'s morning!').
message_on_range(2, 18:00, 20:00, 'it\'s evening!').
comparetime(Hours, Mins) :-
message_on_range(_, Start, Stop, Message),
less_equal_time(Start, Hours:Mins),
less_equal_time(Hours:Mins, Stop),
write(Message), nl.
comparetime(_Hours, _Mins) :-
write('please check your clock!'), nl.
less_equal_time(H1:S1, H2:S2) :-
H1 == H2 -> S1 =< S2 ; H1 < H2.
You should be aware of Prolog features: your problem could require a cut after the message has been printed! I.e.
...
less_equal_time(Hours:Mins, Stop),
write(Message), nl, !.

Resources