Prolog Between two set times - prolog

LONG STORY SHORT
I have a file called timetable.pl that has a pradicate (r,s,t)- r is the name of the train, s is the list of stations it stops at and t is a list of given times for the them stops.
THE file timetable.pl defines a predicate nextTime so that next time(t1,t2) holds if t2 is five minutes after t1.
I have to define a predicate si after t1, t2 holds if t2 is after and before midnight..
I just need some guidance here.

As a starting point, you want to think about a reasonable way to represent times of day.
Prolog lets you use your own functors to structure data as you wish. So you can have name(fred) and process or manipulate this piece of information with code that you write. Prolog doesn't affix any special meaning to it other than knowing it's a functor name and one argument, an atom, fred.
This also works with infix functors. So you can represent a time of day as, HH:MM. For example,
Time = 12:42.
Here, the user-defined functor is : and it has two integer arguments: 12 and 42. This could also be written, ':'(12,42).
If I have a time Time that uses this representation, I can separate out the hours and minutes by unifying it with the functor form:
| ?- Time = 12:42, Time = Hours:Minutes.
Hours = 12
Minutes = 42
Time = 12:42
yes
| ?-
If you have to times, T1 and T2, and they use this representation, you can compare these two times just by comparing their component hours and minutes as integer values. Assuming a 24-hour format, if Time1 = H1:M1 and Time2 = H2:M2, then Time1 is less than Time2 if H1 < H2, or if H1 = H2 and M1 < M2.
This works well for 24-hour time. If you want 12-hour time with an AM/PM designator, you can do it a number of ways, such as, tod(HH:MM, AMPM) (example: tod(12:42, am)), or [HH:MM, AMPM] (example: [12:42, pm]). When having to compare and manipulate times, the 24-hour format is easier. :)

Related

Prolog: Difference relation between two objects

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).

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

SWI Prolog usage of agregation

I created a simple database on SWI Prolog. My task is to count how long each of departments will work depending on production plan. I am almost finished, but I don't know how to sum my results. As for now I am getting something like this
department amount
b 20
a 5
c 50
c 30
how I can transform it to this?
b 20
a 5
c 80
My code https://gist.github.com/senioroman4uk/d19fe00848889a84434b
The code provided won't interpret the count predicate on account of a bad format. You should rewrite it as count:- instead of count():-. As far as I know, all zero-ary predicates need to be defined like this.
Second, your count predicate does not collect the results in a list upon which you could operate. Here's how you can change it to collect all department-amount pairs in a list with findall:
count_sum(DepAmounts):-
findall((Department,Sum),
( productionPlan(FinishedProduct, Amount),
resultOf(FinishedProduct, Operation),
executedIn(Operation, Department, Time),
Sum is Amount * Time
),
DepAmounts
).
Then, over that list, you can use something like SWI-Prolog's aggregate:
?- count_sum(L), aggregate(sum(A),L,member((D,A),L),X).
Which will yield, by backtracing, departments in D and the sum of the amounts in X:
D = a,
X = 15 ;
D = b,
X = 20 ;
D = c,
X = 80.
BTW, if I were you I'd replace all double-quoted strings for department names and operations and etc. for atoms, for simplicity.
you should consider library(aggregate): for instance, calling data/2 the interesting DB subset, you get
?- aggregate(set(K-A),aggregate(sum(V),data(K,V),A),L).
L = [a-5, b-20, c-80]

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