I have a Prolog database that is
dateopened(asda,date(1985,12,5)).
dateopened(tesco,date(1979,12,17)).
dateopened(morrisons,date(1999,12,25)).
dateopened(sainsburys,date(1979,12,17)).
dateopened(lidl,date(1987,8,27)).
I want to find out how to ask the following questions (Prolog queries) to answer the following:
Are there any two distinct supermarkets that opened on the same day and if there are, what are their names?
(I have no idea how to compare items in a database)
Give a year in the 1990s when no supermarkets were opened.
I have tried:
?- dateopened(Supermarket,date(Year,_,_)),Year>1989, Year<2000.
And the result I get is:
Supermarket = morrisons, Year = 1999.
Which sort-of answers the question because I can say that no supermarkets were opened in 1998 or 1997 etc but I don't think this is what is required.
There are a few clues, the questions can be answered using member/2, not/1 and \=.
It's a beginner querying exercise but I have no idea how to start, especially question 1.
As this is a learning exercise, my answer is a little more general, not with a concrete solution:
Question 1: The Prolog interpreter seeks to resolve a query by unifying it with the facts and rules in the fact basis, which form a closed world of known things. To check if something is true according to the facts you just state that in the query so that the solver can try to unify with the facts, using variables in places where you want to obtain a value to work with, and _ as a placeholder for variables whose actual values you don't need. The following query gives you any supermarket, with the full date in a variable.
?- dateopened(S1,Date1).
S1 = asda,
Date1 = date(1985, 12, 5) ;
...
If your query needs multiple conditions met you can combine them with ,, evaluated from left to right. To solve the initial question, you just pick any two supermarkets in the same way using different variables, and afterwards make sure their date is equal and their name is different \=, which reduces the number of possible solutions to what you need.
Question 2: I think your idea is almost of the opposite of what you want, but not really, as the opposite of 1999 would be all the other years. As a solution sketch:
Find a year in the nineties. The predicate between/3 will help, but if you are only allowed the above ones, a list L with the years and member(Year,L) will do.
Use the first part of your initial attempt to reduce the possible years to those when a super market was opened.
Invert that last part using \+ (not/1 is deprecated, assuming SWI-Prolog) so that you find the other years for which we previously made sure they were in range.
Related
I'm studying for an Artificial Intelligence exam and struggling to understand how to answer certain questions focusing on Predicates. The two questions in particular are:
Define a predicate which behaves as follows -
?- stage_name(billie, Name).
Name = rose
yes
?- stage_name(jenna,Name).
Name = clara
yes
Write a predicate that takes two argument and is true if both actors are on the same show. Thus
?-same_show(david,clara).
is true, whilst
?-same_continent(elisabeth,skippy).
is not
I don't really understand how I would answer these questions, and I'm finding very little Prolog information online. I would appreciate some help. Apologies for the formatting.
1:
stage_name(billie,rose).
stage_name(jenna,Name) :- Name=clara.
Explanation:
Given a query, Prolog looks for an appropriate predicate according to the input parameters and the name and "executes" it. The result is either true/false if no output parameter is given. In this case there is one (Name) which can be seen from the leading capital letter. Note that there are two possible ways to implement this. The former is probably the most common (predicates of this form are called "facts" whereas predicates such as the lower are called "rules").
2:
As mentioned in my comment, I don't really understand the connection between the two given predicates. Also it feels like there is something missing such as a facts that determine which person is on which show...
Assuming such facts are missing, I would write the Prolog program as follows:
onShow(david, s1).
onShow(clara, s1).
onShow(bernie, s2).
same_show(P1, P2) :- onShow(P1,X), onShow(P2,X).
Explanation:
The predicate is only true if both P1 and P2 visit the same show X.
Hints:
A "comma" represents a logical AND operator. Having different rules with the same name and parameter count represents logical OR. Edit: As Boris mentioned in a comment, this is not exactly true. This association simply helped me to understand the connection between "Logical Predicates" and "Prolog Predicates".
Visit SWISH to test your Prolog programs.
Years ago in college,I tinkered with some prolog, but that's long forgotten, so I count as a complete beginnner again (humbling!)
Anyway, I was playing with some of Bruce Tate's code, and came up with what I thought was a sudoku solver for the full (9x9) game. But, when I run it, it generates some very odd output:
Solution = [_#3(2..3),_#24(2:7),_#45(2..3:5:7),_#66(2..3:8),_#87(2..3:5..6:8),4,_#121(2:5..6),1,9,6,8,_#194(2..5:7:9),_#215(1..3:9),_#236(2..3:5:9),_#257(1..2:5:9),_#278(2:4..5),_#299(4:7),_#320(5:7),_#341(1..2),_#362(2:4),_#383(2:4..5:9),_#404(1..2:9),_#425(2:5..6:9),7,3,_#472(4:6),8,4,1,_#532(2:8),_#553(2:8),7,3,9,5,6,7,5,_#689(6:8),_#710(4:8..9),_#731(4:6:8..9),_#752(6:8..9),1,2,3,_#828(2..3),9,_#862(2..3:6),5,1,_#909(2:6),7,8,4,8,_#990(2:4:7),1,6,_#1037(2..5:9),_#1058(2:5:9),_#1079(4..5),_#1100(3..4:7),_#1121(5:7),5,_#1163(4:6..7),_#1184(4:6..7),_#1205(1:3..4:8),_#1226(3..4:8),_#1247(1:8),_#1268(4:6:8),9,2,9,3,_#1341(2:4:6),7,_#1375(2:4..5:8),_#1396(1..2:5:8),_#1417(4..6:8),_#1438(4:6),_#1459(1:5)]
yes
I was expecting ... well, frankly I was half expecting total failure :) but I thought that only numbers could show up in this output. What's it trying to tell me with those #-tagged things, and stuff in parens that looks like ranges? Is it trying to say there are many possible solutions and it's telling me all at once (seems unlikely as it's very unhelpful if it is) or is this some kind of error state (in which case, why does it compile my code and say "yes" to this query?)
Any insight gratefully received!
I think it's the result of a set of constraints not sufficiently strong to determine a solution without search. For instance, _#3(2..3) could means that a variable named _#3 could assume values in range 2..3. You could try to label the variables, something like
..., labeling([], Solution).
Syntax details depend on your solver, of course...
This is a somewhat silly example but I'm trying to keep the concept pretty basic for better understanding. Say I have the following unary relations:
person(steve).
person(joe).
fruit(apples).
fruit(pears).
fruit(mangos).
And the following binary relations:
eats(steve, apples).
eats(steve, pears).
eats(joe, mangos).
I know that querying eats(steve, F). will return all the fruit that steve eats (apples and pears). My problem is that I want to get all of the fruits that Steve doesn't eat. I know that this: \+eats(steve,F) will just return "no" because F can't be bound to an infinite number of possibilities, however I would like it to return mangos, as that's the only existing fruit possibility that steve doesn't eat. Is there a way to write this that would produce the desired result?
I tried this but no luck here either: \+eats(steve,F), fruit(F).
If a better title is appropriate for this question I would appreciate any input.
Prolog provides only a very crude form of negation, in fact, (\+)/1 means simply "not provable at this point in time of the execution". So you have to take into account the exact moment when (\+)/1 is executed. In your particular case, there is an easy way out:
fruit(F), \+eats(steve,F).
In the general case, however, this is far from being fixed easily. Think of \+ X = Y, see this answer.
Another issue is that negation, even if used properly, will introduce non-monotonic properties into your program: By adding further facts for eats/2 less might be deduced. So unless you really want this (as in this example where it does make sense), avoid the construct.
I have been assigned to do some work on PROLOG, I have made a very good attempt at one question where I was suppose to find the largest number of pages for a single article by a certain author.
What I have so far is:
A= Author
P = Pages
Pages(A,N) :- Database(A,_,_,_,N,_).
getpages(X) :- findall(A,pages(_,A),X).
getauthor(X) :- findall(A,pages(A,_),X).
printlist([A|N]) :- print(A), nl,pages(A,N).
Once I run a query for findall I get the numbers of pages but not in descending order, showing the highest value, how do I do that?
I have an idea of using sumlist and/or printlist somehow.
Also how do I find something in a database Starting with 'abc' or whatever.. I know in sql you have a function to do that, but how is it done in PROLOG? I want to find all the articles starting with 'IEEE'.
If you are wondering how to print a list in ascending order, you just have to sort it first. There is a builtin predicate, sort/2, that you can use for sorting a list in ascending order.
Check the SWI-Prolog documentation for details. If there are possible duplicates that you don't want to eliminate, use msort/2 instead.
You could write a predicate that gets the pages in ascending order like this:
getpages_sorted(X) :- findall(A, pages(_, A), Unsorted), sort(Unsorted, X).
It would also be wise to choose representative names for your variables, code clarity plays an integral part at debugging in prolog.
setof/3 instead of findall/3 will do, but you have to qualify free variables scope to properly use it, since variables binding plays a very important role in Prolog execution:
getpages(X) :- setof(A,S^pages(S,A),X).
library(aggregate) will put in your hands more constructs ready to use, similar to what's available in SQL, but you should first try to understand well setof/3.
Prolog doesn't have 'select ... where ... LIKE ...'. Symbols are used for identity, while in SQL (intended as relational calculus), identity is by record. This is a shortcoming when moving logic from relational RDBMs to Prolog, similar to the case insensitiveness that RDBMs implement. A COLLATION it's not a concept of Prolog...
So, when you ask
how do I find something in a database Starting with 'abc' or whatever..
you should implement your own matching algorithm, for instance
page(Author, _Title) :- sub_atom(Author,_,_,_,abc).
would match any page having 'abc' in Author atom, similar to
select Author from page where Author like '%abc%'
edit sub_atom/5 it's rather powerful: for instance, to peek atoms starting with abc
1 ?- sub_atom(abcd,0,_,_,abc).
true.
2 ?- sub_atom(zabcd,0,_,_,abc).
false.
So from what I understand about deterministic predicates:
Deterministic predicate = 1 solution
Non-deterministic predicate = multiple solutions
Are there any type of rules as to how you can detect if the predicate is one or the other? Like looking at the search tree, etc.
There is no clear, generally accepted consensus about these notions. However, they are usually based rather on the observed answers and not based on the number of solutions. In certain contexts the notions are very implementation related. Non-determinate may mean: leaves a choice point open. And sometimes determinate means: never even creates a choice point.
Answers vs. solutions
To see the difference, consider the goal length(L, 1). How many solutions does it have? L = [a] is one, L = [23] another... but all of these solutions are compactly represented with a single answer substitution: L = [_] which thus contains infinitely many solutions.
In any case, in all implementations I know of, length(L, 1) is a determinate goal.
Now consider the goal repeat which has exactly one solution, but infinitely many answers. This goal is considered non-determinate.
In case you are interested in constraints, things become even more evolved. In library(clpfd), the goal X #> Y, Y #> X has no solution, but still one answer. Combine this with repeat: infinitely many answers and no solution.
Further, the goal append(Xs, Ys, []) has exactly one solution and also exactly one answer, nevertheless it is considered non-determinate in many implementations, since in those implementations it leaves a choice point open.
In an ideal implementation, there would be no answers without solutions (except false), and there would be non-determinism only when there is more than one answer. But then, all of this is mostly undecidable in the general case.
So, whenever you are using these notions make sure on what level things are meant. Rather explicitly say: multiple answers, multiple solutions, leaves no (unnecessary) choice point open.
You need understand the difference between det, semidet and undet, it is more than just number of solutions.
Because there is no loop control operator in Prolog, looping (not recursion) is constructed as a 'sequence generating' predicate (undet) followed by the loop body. Also you can store solutions with some of findall-group predicates as a list and loop later with the member/2 predicate.
So, any piece of your program is either part of loop construction or part of usual flow. So, there is a difference in designing det and undet predicates almost in the intended usage. If you can work with a sequence you always do undet and comment it as so. There is a nice unit-test extension in swi-prolog which can check wheter your predicate always the same in mean of det/semidet/undet (semidet is for usage the same way as undet but as a head of 'if' construction).
So, the difference is pre-design, and this question should not be arised with already existing predicates. It is a good practice always comment the intended usage in a comment like.
% member(?El, ?List) is undet.
Deterministic: Always succeeds with a single answer that is always the same for the same input. Think a of a static list of three items, and you tell your function to return value one. You will get the same answer every time. Additionally, arithmetic functions. 1 + 1 = 2. X + Y = Z.
Semi-deterministic: Succeeds with a single answer that is always the same for the same input, but it can fail. Think of a function that takes a list of numbers, and you ask your function if some number exists in the list. It either does, or it doesn't, based on the contents of the list given and the number asked.
Non-deterministic: Succeeds with a single answer, but can exhibit different behaviors on different runs, even for the same input. Think any kind of math.random(min,max) function like random/3
In essence, this is entirely separate from the concept of choice points, as choice points are a function of Prolog. Where I think the Prolog confusion of these terms comes from is that Prolog can find a single answer, then go back and try for another solution, and you have to use the cut operator ! to tell it that you want to discard your choice points explicitly.
This is very useful to know when working with Prolog Unit Testing