"strptime" in SWI-Prolog - prolog

How to convert atom '2015-12-15T05 PST' to timestamp or datetime?
I've tried parse_time/3
?- parse_time('2015-12-15T05 PST', '%Y-%m-%dT%H %Z', Stamp)
false.
and format_time/3
?- format_time('2015-12-15T05 PST', '%Y-%m-%dT%H %Z', date(Y,M,D,H,M,S,O,TZ,DST)).
ERROR: format_time/3: Arguments are not sufficiently instantiated

According to the documentation, the mode of format_time/3 can't really help you, because it's expecting everything to be passed in:
format_time(+Out, +Format, +StampOrDateTime)
This means you supply each of the arguments. You want to see something with a - prefix which means it's handing something back, which seems like it would mean parse_time/3, but there the documentation says:
Supported formats for Text are in the table below.
and it then proceeds to list exactly two options, rfc_1123 and iso_8601, neither of which really match your format. There does not seem to be a way to supply a format code here, which I find really puzzling, because there are underlying Unix libraries here that can certainly do this.
However, the problem can be solved with everyone's favorite tool: definite clause grammars! Here's my solution:
:- use_module(library(dcg/basics)).
myformat(date(Y,M,D,H,_,_,_,TZ,_)) -->
integer(Y), "-", integer(M), "-", integer(D),
"T", integer(H), " ", timezone(TZ).
timezone('UTC') --> "UTC".
timezone('UTC') --> "GMT".
timezone(-18000) --> "PST".
timezone(Secs) -->
[Sign], digit(H0), digit(H1), digit(M0), digit(M1),
{
(Sign = 0'+ ; Sign = 0'-),
number_codes(Hour, [H0,H1]),
number_codes(Minutes, [M0, M1]),
(Sign = 0'+
-> Secs is Hour * 3600 + Minutes * 60
; Secs is -(Hour * 3600 + Minutes * 60))
}.
my_time_parse(Atom, Date) :-
atom_codes(Atom, Codes),
phrase(myformat(Date), Codes).
I'm sure the learned will see ways to improve this code but it did the trick for me with your sample data. You will unfortunately need to either enumerate timezones or find a better source of data on them (perhaps parsing the system timezone definitions?) but if you know a-priori that you only need to handle PST, you can try it. Here's an example:
?- my_time_parse('2015-12-15T05 PST', Date).
Date = date(2015, 12, 15, 5, _G3204, _G3205, _G3206, -18000, _G3208) ;
false.
Hope this helps!

Coming late to this question: the desired format is close to iso_8601, which would take the format "2015-12-15T05-08". To replace the time zone " PST" with "-08", we can use append. For code:
:- set_prolog_flag(double_quotes, chars).
timezone(" PST", "-08").
timezone(" PDT", "-07").
%% etc
convert_time(Date, Stamp) :-
timezone(Zone, Delta),
append(Front, Zone, Date),
append(Front, Delta, Date2),
string_chars(Date3, Date2),
parse_time(Date3, iso_8601, Stamp).
test :-
convert_time("2015-12-15T05 PST", Stamp),
writeln('Stamp'=Stamp),
fail.
with output
?- test.
Stamp=1450184400.0
false.

Related

Prolog output message understanding

This is a really quick one, I don't know the correct way to google it!
Say we have an output such it gives:
X = [4|_1218]
what generally has to be changed to get the output just to say 4?
member1(Head, [Head|_]):-!.
member1(Item, [_|Tail]):-
member1(Item, Tail).
findnotin([Head|_], RuledOut, [Head|_]):-
not(member1(Head, RuledOut)).
Edit Completedish program:
find_not_in([], _, _).
find_not_in([Head|Candidates], RuleOut, [Head|Legal]):-
not(member1(Head, RuleOut)),
find_not_in(Candidates, RuleOut, Legal).
find_not_in([_|Candidates], RuleOut, Legal):-
find_not_in(Candidates, RuleOut, Legal).

Prolog - fail; true

I have some problem with my code here.
Let's say I have a knowledge base like this:
university('University of Cambridge', 1, 'United Kingdom', 90.3, 92.8, 89.4).
university('University of Oxford', 2, 'United Kingdom', 88.9, 94.8, 88.0).
university('ETH Zurich - Swiss Federal Institute of Technology', 3, 'Switzerland', 86.4, 94.4, 92.2).
university('University of Edinburgh', 4, 'United Kingdom', 83.7, 88.8, 83.6).
Then I call it out like this:
(Ignore the checkC(Country)/checkC(_))
checkC(Country):-
university(U, R, Country, _, _, _),nl,
write('University: '),write(U),nl,
write('Rank: '),write(R),nl,
write('Country: '),write(Country),nl,
fail; true, nl,
write('************'), nl,nl.
checkC(_):-
write('Country not found'),nl,nl.
My question is, why is it if the user inputs a random country name not within the knowledge base, the write('Country not found') won't come out, I found out that it has something to do with the fail; true.
Any help?
While the fail; true trick is nice for the command line, gathering multiple solutions is usually done via the predicates findall, bagof and setof.
I used format for readabilities sake.
checkC(X):-
findall( [U,R,X], university(U,R,X,_,_,_), List),
(List = [] ->
write('Country not found\n\n');
writeCountries(List)).
writeCountries([]).
writeCountries([X|R]):-
writeCountries(R),
format('University: ~w~nRank: ~w~nCountry: ~w~n~n',X).
If you are using swipl, maplist comes in handy:
checkC(X):-
findall( [U,R,X], university(U,R,X,_,_,_), List),
(List = [] ->
write('Country not found\n\n');
maplist(format('University: ~w~nRank: ~w~nCountry: ~w~n~n'),List)).
If you don't have format/2 look if you have writef/2 or printf/2.

Prolog Query Exercise - Beginner

I'm a begginer at Prolog and I need some help with this exercise, this is the knowledge base provided:
album(‘R. Stevie Moore’, ‘Manuscription’).
album(‘Lane Steinberg’, ‘Manuscription’).
album(‘R. Stevie Moore’, ‘The Yung & Moore Show’).
album(‘Yukio Yung’, ‘The Yung & Moore Show’).
album(‘Jessie Evans’, ‘Autonervous’).
album(‘Bettina Koster’, ‘Autonervous’).
album(‘Lucia Pamela’, ‘Walkin on the moon’).
album(‘Shooby Taylor’, ‘The Human Horn’).
album(‘Tiny Tim’, ‘God Bless Tiny Tim’).
album(‘The Legendary Stardust Cowboy’, ‘Rock-It to Stardom’).
vinil(‘Rock-It to Stardom’).
vinil(‘Walking on the Moon’).
cd( ‘God Bless Tiny Tim’).
cd(‘Walking on the Moon’).
cd(‘Autonervous’).
cd(‘Manuscription’).
cassette(‘The Human Horn’).
cassette(‘The Yung & Moore Show’).
mp3(‘Walkin on the Moon’).
I need to make a query that will return to me all the albums that were made by only one musician.
Thanks for your help :)
In the comments you have provided your code album(X,B),album(Y,C), B \= C. Actually, this is not too far away from a correct solution.
A correct solution could be:
one_musician_album(X) :-
album(A, X),
\+ (album(B, X), A \= B).
The meaning of the predicate is: an album X is a "one-musician album" if this album is authored by some musician A and it's not possible to find a different musician B authored the album X.
Test run:
?- one_musician_album(X).
X = 'Walkin on the moon' ;
X = 'The Human Horn' ;
X = 'God Bless Tiny Tim' ;
X = 'Rock-It to Stardom'.
To get all answers you have to type ';' after each answer.
Maybe this is not needed for you, but it's possible to get all answers in a list with findall:
?- findall(X, one_musician_album(X), Albums).
Albums = ['Walkin on the moon', 'The Human Horn', 'God Bless Tiny Tim', 'Rock-It to Stardom'].
Here is a generalization, based on 'all solutions' builtin bagof/3.
Note that
?- bagof(A, album(A,T), As).
T = 'Autonervous',
As = ['Jessie Evans', 'Bettina Koster'] ;
T = 'God Bless Tiny Tim',
As = ['Tiny Tim']
....
then, restricting the authors (As) to be a list of a single element, we get albums with a single author
?- bagof(A, album(A,T), [A]).
A = 'Tiny Tim',
T = 'God Bless Tiny Tim' ;
...
then, we could use findall/3, as in the good answer by Sergey, or, again, bagof/3, with explicit quantification:
?- bagof(T, A^bagof(A, album(A, T), [A]), Ts).
Ts = ['God Bless Tiny Tim', 'Rock-It to Stardom', 'The Human Horn', 'Walkin on the moon'].

Prolog find minimum in list error

Im trying to make my code work, but somehow I got stuck on a problem, Im very newbie to prolog. This is my code.
dist(valmiera, riga, 107).
%dist(riga, valmiera, 107).
dist(cesis, riga, 70).
dist(valmiera, rujiena, 50).
dist(rujiena, valka, 30).
dist(valmiera, strenci, 200).
dist(strenci, valka, 30).
dist(valmiera, cesis, 40).
dist(liepaja, saldus, 100).
dist(saldus, riga, 200).
dist(liepaja, jelgava, 270).
dist(jelgava, riga, 50).
path(A,B,C,[A,B]):- dist(A,B,C).
path(A,B,D,[A|As]):- dist(A,W,C), path(W,B,E,As), D is C+E.
%, findMin(YList, E), path(A,B,X,E),!.
shortestPath(A,B,X,E):-findall(Y,path(A,B,S,Y),YList), findMin(YList, E), path(A,B,X,E),!.
findMin([],fail).
findMin([H],E):-E=H,!.
findMin([H,V],E):-H<V, E=H,!; V<H, E=V, !; H=:=V, E=H, !.
findMin([H|T],E):-findMin(T,U), H<U, E=H,!;findMin(T,U), U<H, E=U,!;findMin(T,U), U=:=H, E=U,!.
but when I call findMin() I get this error
uncaught exception: error(type_error(evaluable,'.'/2),(<)/2)
I'm realy stuck and don't know what to do. Any help will be appreciated.
Applications purpose is get shortest path by calling shortestPath(), paths are in dist (a,b,distance)
The exception is because the terms you are trying to compare are lists.
[liepaja,saldus,riga]<[liepaja,jelgava,riga] ?
An expression:
Term1 < Term2
succeeds if
eval(Term1) < eval(Term2)
So, Term1 and Term2 have to be evaluable terms (e.g., (1+1)<(2+2)).
Try to change the shortestPath/4 body:
shortestPath(A,B,X,E):-
findall(couple(W,P),path(A,B,W,P),WP_List),
findMin(WP_List, couple(Weight,ShortestPath)),...
In this way you have a list of couple(Weight,Path) and in findMin you can get the Weight per Path.

DCG output single variable instead of whole clause in a list

I have a problem, while creating a question answer Prolog file. I have a database with locations and I can already get the question and write the answer out. But there are different types of objects, that require different prefixes. So I defined DCG for prefixes.
answer(P,A) :- location(P, Str, Nr),A = [there, is, article(G,K,N,P), noun(G,K,N,P), pre(P),Str,Nr].
question(A) --> questionsentence(P),{answer(P,A)}.
pre(P) --> [in, P], {member(P, [road66])}.
pre(P) --> [at, P], {member(P, [trafalgarsquare])}.
but what i get is something like this:
?-question(A, [where,is,a,kentuckys],[]).
A = [there, is, article(_G2791, _G2792, _G2793, kentuckys), noun(_G2791, _G2792, _G2793, kentuckys), prep(kentuckys), road66, 123]
This works for verifying the input properly, but it seems to be useless for the output. How can I take just the variable and not the clause?
OK, I tried to translate the whole program to a more or less usefull and working example.
location(kentuckys, road66, 121).
location(soliver, trafalgarsquare, 15).
location(marcopolo, trafalgarsquare, 15).
location(internist, jumpstreet, 21).
questionsentence(P,G) --> [where],[is], article(G), noun(G,P).
answer(P,A,G) :- location(P, Str, Nr), prep(W,Str), article(G,Art,[]), flatten([there, is, Art, P, W, Str,Nr], A).
question(A) --> questionsentence(P,G),{answer(P,A,G)}.
article(m) --> [a].
article(f) --> [an].
noun(m, P) --> [P], {member(P, [kentuckys, soliver, marcopolo])}.
noun(f, P) --> [P], {member(P, [internist])}.
prep([at],Str) :- member(Str, [trafalgarsquare, road66]).
prep([in],Str) :- member(Str, [jumpstreet]).
Result:
?- question(A, [where,is,a,kentuckys],[]).
A = [there, is, a, kentuckys, at, road66, 121] .
I think, what I looked for was a construction like: article(G,Art,[]) to determine the depending DCG variable... actually I do not fathom yet how the two last arguments are working...

Resources