Prolog is the Fortran of logic programming: it was the first of its kind, it was much criticised, and it is still widely used.
George Santayana: "Those who do not remember the past are condemned to repeat it."
Tim Menzies: "Those who do not study Prolog are condemned to repeat it."
PROLOG came from natural langauge research in the 1970s, 1980s and was an attempt to treat human texts as logic formulae. Hence, before we can explain NL in PROLOG, we must explain PROLOG.
Functions map inputs to outputs.
Predicates define constraints on variables.
Functions run.
Predictes match.
Functions return some output.
Predicates only return yes or no. If "yes", then as a side effect, they may add bindings to variables.
(Adapted from Robert F. Rossa: rossa@csm.astate.edu).
We show below a Prolog program consisting entirely of simple clauses or facts. This set of facts is a database about a family.
/* family.pl - a simple database for a family */ gender(al,male). gender(anne,female). gender(arthur,male). gender(amber,female). gender(boris,male). gender(barbara,female). gender(betty,female). gender(buck,male). gender(carla,female). gender(charles,male). gender(cora,female). gender(cuthbert,male). gender(cecilia,female). gender(calvin,male). father(arthur,buck). father(al,buck). father(amber,buck). father(anne,boris). father(barbara,charles). father(betty,cuthbert). father(boris,charles). father(buck,calvin). mother(al,barbara). mother(anne,betty). mother(arthur,barbara). mother(amber,barbara). mother(boris,carla). mother(barbara,carla). mother(betty,cora). mother(buck,cecilia).
We can load this database into a Prolog interpreter.
swipl -f family.pl ?-
Now the interpreter is waiting for us to query it. Every query must end with a period. When we query the interpreter, it will give us the first answer it finds, based on the facts in the database. If we want more answers, we enter a semicolon. If we don't want any more answers to that query, we just enter a carriage return. Thus consider the sequence that follows.
?- father(X,Y). X=arthur, Y=buck; X=al, Y=buck; X=amber, Y=buck; X=anne, Y=boris; X=barbara, Y=charles; X=betty, Y=cuthbert; X=boris, Y=charles; X=buck, Y=calvin no ?-
So the Father successed many times, and as a side-effect, printed some bindings. Then it automatically backtracked (on the ";" command) to find other bindings.
In this example, PROLOG answers "no" since no data satisfies the following constraints.
?- mother(al,betty). no ?- mother(al,barbara). yes ?-We can build more complex queries like the following, to find a grandmother of al.
?- mother(al,X),mother(X,Y). X=barbara, Y=carla yes ?-
Which is to say that we are looking for a pattern and where "X" and "Y" satisfy some constraints.
BTW, identifiers that start with an upper case letter are variables, and those that start with lower case letters are constants.
parent(X,Y) :- father(X,Y). parent(X,Y) :- mother(X,Y).The symbol ':-' should be read as "if". Now we can query as follows.
?- parent(al,Y). Y=buck; Y=barbara yes ?-We can now build a rule that uses the parent rules.
grandfather(X,Y) :- parent(X,Z),father(Z,Y).and ask questions like
?- grandfather(anne,Y). Y=charles; Y=cuthbert; no ?-
Note that PROLOG has no pre-defined input output variables- everything is a constraint. So we could have equally posed the above query as:
?- grandfather(X,anne). X=anne; no ?-
The scope of variables is one clause; there is no such thing as a global variable.
When Prolog tries to answer a query, it goes through a matching process. It tries to match the predicates on the right-hand side of the rule from left to right, binding variables when it finds a match. If a match fails, it may be because of the bondings in matches to the left. In that case, the interpreter backtracks - it returns to the nearest previous binding and tries to find a different match. If that fails, it backtracks some more.
We can make Prolog print out all the answers to a question by deliberately making it fail, using the fail predicate.
?- grandfather(X,Y),write('X='),write(X),write(', Y='),write(Y),nl,fail. X=arthur, Y=calvin X=al, Y=calvin X=amber, Y=calvin X=anne, Y=charles X=al, Y=charles X=anne, Y=cuthbert X=arthur, Y=charles X=amber, Y=charles no ?-
Prolog lists have heads and tails (think "car" and "cdr").
member(A, [A|_]). member(A, [_|B]) :- member(A, B).
So, of course,...
?- member(a,[c,b,a]). true
But Prolog can bactrack to find all repeated members of a list:
?- member(a,[c,a,b,a]). true ; true
Also, we can find all members of a list:
?- member(X,[a,b,c]). X = a; X = b; X = c
Also, Prolog is a relational language. Variables are not inputs and outputs but concepts woven together by constraints. Also, we only need to partially specify the I/O to query those constraints:
?- member(name=What, [age=20,shoesize=12,name=tim]). What = tim .
(If this is causing stress, just chant to yourself: in Prolog, we don't code; rather, we draw the shape of the solution.)
This can get really funky. Here's the standard definition of how to append two lists:
append([], A, A). append([A|B], C, [A|D]) :- append(B, C, D).
Which works in the expected way:
?- append([a,b,c],[d,e,f],Out). Out = [a, b, c, d, e, f].
But any of these arguments can be left unspecified to achieve neat results:
; find the third thing in a list ?- append([ _, _, Third], _, [alice,john,mike,tim,veronica,wendy]). Third = mike ; find the list before "tim" ?- append(Before, [tim | _], [alice,john,mike,tim,veronica,wendy]). Before = [alice, john, mike] ; find the list after "tim" ?- append(_, [tim | After], [alice,john,mike,tim,veronica,wendy]). After = [veronica, wendy]
You can even write "member" using "append":
member1(X,L) :- append(_,[X|_],L). ?- member1(a,[b,c,a]). true . ?- member1(X,[b,c,a]). X = b ; X = c ; X = a ; fail.
Now with great power comes great responsbility. If you ask find all lists which can contain 'a', you can get an infinite set (of course).
?- member(a,L). L = [ a |_G246] ; L = [_G245, a |_G249] ; L = [_G245, _G248, a |_G252] ; L = [_G245, _G248, _G251, a |_G255] ; L = [_G245, _G248, _G251, _G254, a |_G258] ; L = [_G245, _G248, _G251, _G254, _G257, a |_G261] ; L = [_G245, _G248, _G251, _G254, _G257, _G260, a |_G264] ; L = [_G245, _G248, _G251, _G254, _G257, _G260, _G263, a |_G267] ;
Lesson: logic, like anything else, must be used wisely.
(Written by yours truly.)
Prolog variables support generalizations. For example, the following monkeys and bananas solution supports climbing onto a box anywhere in the room as well as push anything to anywhere.
It uses the following database:
% making Move in State1 results in State2; % move( State1, Move, State2) % representing the current state % state( MonkeyHorizontal, MonkeyVertical, BoxPosition, HasBanana)
Our goal is to get the banana.
goal(state(_,_,_,has)).
Our start state...
start(state(atfloor,onfloor,atwindow,hasnot)).
This is how we can get from state1 to state2:
canget( S,[]) :- goal(S). % base case canget( State1,[Act|Rest]) :- % general case move( State1, Act, State2), % Do something canget( State2,Rest). % Repeat
The knowledge base:
move( state( middle, onbox, middle, hasnot), % Before move grasp, % Grasp banana state( middle, onbox, middle, has) ). % After move move( state( P, onfloor, P, H), climb, % Climb box state( P, onbox, P, H) ). move( state( P1, onfloor, P1, H), push( P1, P2), % Push box from P1 to P2 state( P2, onfloor, P2, H) ). move( state( P1, onfloor, B, H), walk( P1, P2), % Walk from P1 to P2 state( P2, onfloor, B, H) ).
Main program:
main :- start(S0), canget(S0, Steps), forall(member(Step,Steps), (print(Step),nl)).
Output:
?- main. walk(atfloor, atwindow) push(atwindow, middle) climb grasp true ;
We pause here (even though we asked PROLOG to backtrack and find more solutions with the ";" command) to comment that we we got to the bananas.
Moving on, as we backtrack, we see that the solution gets longer. This is not a bug. What is going on?
walk(atfloor, atwindow) push(atwindow, _G251) push(_G251, middle) climb grasp true ; % new solution found walk(atfloor, atwindow) push(atwindow, _G251) push(_G251, _G262) push(_G262, middle) climb grasp true ; % another solution found walk(atfloor, atwindow) push(atwindow, _G251) push(_G251, _G262) push(_G262, _G273) push(_G273, middle) climb grasp true . % yet another solution found
Hmm.... looks like we need to control how far the money walks.
(Adapted from John Fisher's excellent Prolog tutorial.)
Prolog's hardwired search is depth-first through its list of clauses. But this can easily be changed. For example, in this section we will code up DFID in Prolog.
For our first DFID, we control the size of the list that shows the steps taken to reach the goal. We can build that leash using the following trick:
?- between(1,5,N), length(List, N). N = 1, List = [_G292] ; N = 2, List = [_G292, _G295] ; N = 3, List = [_G292, _G295, _G298] ; N = 4, List = [_G292, _G295, _G298, _G301] ; N = 5, List = [_G292, _G295, _G298, _G301, _G304].
We will use this trick to define dfid as a loop around the monkey's "canget" predicate:
dfid(Max) :- start(S0), between(1,Max,Depth), % on backtracking, Depth=1,2,3,... length(Steps,Depth), % Steps is a list of size Depth print(leash(Steps)),nl, canget(S0,Steps), print(Depth),nl, forall(member(Step,Steps), (tab(4),print(Step),nl)).
For example:
?- dfid(5), fail. % backtrack through all solutions. leash([_G254]) leash([_G254, _G257]) leash([_G254, _G257, _G260]) leash([_G254, _G257, _G260, _G263]) 4 walk(atfloor, atwindow) push(atwindow, middle) climb grasp leash([_G254, _G257, _G260, _G263, _G266]) 5 walk(atfloor, atwindow) push(atwindow, _G280) push(_G280, middle) climb grasp 5 walk(atfloor, atwindow) push(atwindow, middle) walk(middle, middle) climb grasp 5 walk(atfloor, _G272) walk(_G272, atwindow) push(atwindow, middle) climb grasp
Prolog has a shorthand for writing grammar rules:
sentence --> nominal_phrase, verbal_phrase. verbal_phrase --> modlist,verb. nominal_phrase --> article, noun. article --> [the]. noun --> [dog]. verb --> [runs]. verb --> [barks]. modlist --> []. modlist --> [sadly], modlist.
(Note that modlist is zero or more "sadly"s.).
If we load this into PROLOG, we get
swipl -f english.pl ?- listing(sentence). sentence(A, C) :- nominal_phrase(A, B), verbal_phrase(B, C). true. ?- listing(verb). verb([runs|A], A). verb([barks|A], A). true. ?-
That is, PROLOG interprets grammars as rules. Terminals (like runs) are assumed to be members of a list.
We can ask PROLOG now, what sentences are valid in this grammar:
?- sentence(X,[]). X = [the, dog, runs] ; X = [the, dog, barks]; no ?-
We can also ask, is a sentence valid:
?- sentence([the,dog,runs],X). X = [] . ?- sentence([the,dog,sadly,sadly,sadly,runs],X). X = [] . ?- sentence([the,dog,flies],X). false. ?-
What is wrong with this grammar?
s --> np, vp. np --> det, n. np --> pro. vp --> v, np. vp --> v. det --> [the]. det --> [a]. n --> [woman]. n --> [man]. v --> [shoots]. pro --> [he]. pro --> [she]. pro --> [him]. pro --> [her].
Seems to work ok...
?- s([she,shoots,him],[ ]). yes ?- s([a,woman,shoots,him],[ ]). yes
But these sentences are odd...
?- s([a,woman,shoots,he],[ ]). yes ?- s([her,shoots,a,man],[ ]). yes s([her,shoots,she],[ ]). yes
The DCG ignores some basic facts about English
It is obvious what we need to do:
How do we do this? Version 1 (verbose, naive):
s --> np_subject, vp. np_subject --> det, n. np_object --> det, n. np_subject --> pro_subject. np_object --> pro_object. vp --> v, np_object. vp --> v. det --> [the]. det --> [a]. n --> [woman]. n --> [man]. v --> [shoots]. pro_subject --> [he]. pro_subject --> [she]. pro_object --> [him]. pro_object --> [her].
Nice way using extra arguments:
s --> np(subject), vp. np(_) --> det, n. np(X) --> pro(X). vp --> v, np(object). vp --> v. det --> [the]. det --> [a]. n --> [woman]. n --> [man]. v --> [shoots]. pro(subject) --> [he]. pro(subject) --> [she]. pro(object) --> [him]. pro(object) --> [her].
Better:
?- s([she,shoots,him],[ ]). yes ?- s([she,shoots,he],[ ]). no ?-
What is really going on? Recall that the rule:
s --> np,vp.is really syntactic sugar for:
s(A,B):- np(A,C), vp(C,B).The rule
s --> np(subject),vp.translates into:
s(A,B):- np(subject,A,C), vp(C,B).so, in effect, we have added a guard to the computation.
DCG that builds parse tree
s(s(NP,VP)) --> np(subject,NP), vp(VP np(_,np(Det,N)) --> det(Det), n(N). np(X,np(Pro)) --> pro(X,Pro). vp(vp(V,NP)) --> v(V), np(object,NP). vp(vp(V)) --> v(V)). det(det(the)) --> [the]. det(det(a)) --> [a]. n(n(woman)) --> [woman]. n(n(man)) --> [man]. v(v(shoots)) --> [shoots]. pro(subject,pro(he)) --> [he]. pro(subject,pro(she)) --> [she]. pro(object,pro(him)) --> [him]. pro(object,pro(her)) --> [her].
?- s(T,[he,shoots],[]). T = s(np(pro(he)),vp(v(shoots))) yes
It turns out that tree-traversal and computation are closely linked. E.g. descending into a tree based on a certain symbol is the same a conditional block with a guard.
PROLOG adds a {X} construct to its grammar rules that let you do primitive computations.
number(0) --> [zero]. number(N) --> digit(H), [hundred], and_tens(T), {N is H * 100 + T}. number(N) --> sub_tens(N). and_tens(0) --> []. and_tens(N) --> [and], sub_tens(N). sub_tens(N) --> digit(N). sub_tens(N) --> teen(N). sub_tens(N) --> tens(T), and_digit(D), {N is T + D}. and_digit(0) --> []. and_digit(N) --> digit(N). digit(1) --> [one]. teen(10) --> [ten]. digit(2) --> [two]. teen(11) --> [eleven]. digit(3) --> [three]. teen(12) --> [twelve]. digit(4) --> [four]. teen(13) --> [thirteen]. digit(5) --> [five]. teen(14) --> [fourteen]. digit(6) --> [six]. teen(15) --> [fifteen]. digit(7) --> [seven]. teen(16) --> [sixteen]. digit(8) --> [eight]. teen(17) --> [seventeen]. digit(9) --> [nine]. teen(18) --> [eighteen]. teen(19) --> [nineteen]. tens(20) --> [twenty]. tens(30) --> [thirty]. tens(40) --> [forty]. tens(50) --> [fifty]. tens(60) --> [sixty]. tens(70) --> [seventy]. tens(80) --> [eighty]. tens(90) --> [ninety].
The associated program now responds to queries of the following type:
[user] ?- number(Value, [ two, hundred, and, twenty, three ], []). Value = 223 yes
Besides performing this syntactical analysis and calculating the value, the program is also capable of providing an appropriate verbal expression for a given value (synthesis).
[user] ?- number(101, X, []). X = [one,hundred,and,one]
Can a computer understand a human? Lets test that. Let human ask questions about a domain and see if the machine can understand those questions w.r.t. the background knowledge of that domain?
It turns out this is a three-part problem:
a, some, the[singular] exists(X,R & S) no not exists(X,R & S) every, all not exists(X,R & not S) the[plural] exists(X,setof(X,R,X) & S) one, two, ... numeral(N) numberof(X,R & S,N) which, what answer(X) <= R & S how many answer(N) <= numberof(X,R & S,N)
Some birds migrate.
exists(X,bird(X) & migrates(X)).
The population of Britain exceeds 50 million.
exists(X,population(britain,X) & X > 50000000).There are no rivers in Antarctica.
not exists(X,river(X) & in(X,antarctica)).Man inhabits every continent.
not exists(X,continent(X) & not inhabits(man,X)).Jupiter is the largest of the planets.
exists(X,setof(X,planet(X),X) & largest(X,jupiter)).The Rhine flows through three countries.
numberof(X,country(X) & flows through(rhine,X),3).Which birds migrate?
answer(X) <= bird(X) & migrates(X).
How many countries export oil?
answer(N) <= numberof(X,country(X) & exports(X,oil),N).
Which European country exports no arms to coun- tries in Africa?
answer(C) <= european(C) & country(C) & not exists(X, arm(X) & exists(C1, country(C1) & in(Cl,africa) & exports(C,X,C1) ) )
"For any C, C is an answer if C is European and C is a country and it cannot be shown that there is some X such that X is an armament and there is some C1 such that C1 is a country and C1 is in Africa and C exports X to CI"
Move common tests out of inner loop. Peek at the size of each DB and match on smaller things before longer things.
answer(C) <= country(C) & borders (C,mediterranean) & exists(Cl,country(C1) & asian(C1) & borders(C,C 1))After planning, the logical form is transformed into:
answer(C) <= borders(C,mediterranean) & {country(C)} & {borders(C,C1) & {asian(C1) & {country(C1)}}}
Countries
... country(uruguay,south_america,-32,55,68548,2990000,montevideo,peso). country(venezuela,south_america,8,65,352143,11520000,caracas,bolivar). country(vietnam,southeast_east,17,-107,126436,41850000,hanoi,dong). country(west_germany,western_europe,52,-9,95815,61970000,bonn,deutsche_mark). country(western_samoa,australasia,-14,172,1133,150000,apia,tala). country(yemen,middle_east,15,-44,75289,1600000,sana,rial). country(yugoslavia,southern_europe,44,-20,98766,21126000,belgrade,dinar). country(zaire,central_africa,-3,-23,905063,23560000,kinshasa,zaire). country(zambia,southern_africa,-15,-28,290724,4640000,lusaka,kwacha). country(zimbabwe,southern_africa,-20,-30,150333,5690000,salisbury,rhodesian_dollar).Rivers:
... river(senegal_river,[atlantic,senegal,mali,guinea]). river(tagus,[atlantic,portugal,spain]). river(vistula,[baltic,poland]). river(volga,[black_sea,soviet_union]). river(volta,[atlantic,ghana,upper_volta]). river(yangtze,[pacific,china]). river(yenisei,[arctic_ocean,soviet_union,mongolia]). river(yukon,[pacific,united_states,canada]). river(zambesi,[indian_ocean,mozambique,zambia,angola]).World:
flows(R,C1,C2) :- river(R,L), links(L,C2,C1). first([X|_],X). last([X],X). last([_|L],X) :- last(L,X). links([X1,X2|_],X1,X2). links([_|L],X1,X2) :- links(L,X1,X2).Borders:
borders(persian_gulf,saudi_arabia). borders(persian_gulf,united_arab_emirates). borders(red_sea,israel). borders(red_sea,jordan). borders(red_sea,saudi_arabia). borders(red_sea,yemen). borders(red_sea,egypt). borders(red_sea,ethiopia). borders(red_sea,sudan).Contains
contains0(west_germany,hamburg). contains0(west_germany,rhine). contains0(yugoslavia,danube). contains0(zaire,congo_river). contains0(zambia,congo_river). contains0(zambia,zambesi).
Parse: 0.0168457sec. whq $VAR 1 s np 3+plu np_head int_det(B) [] river [] verb(be,active,pres+fin,[],pos) void [] Semantics: 0.0170898sec. answer([B]) :- river(B) & exists B true Planning: 0.0sec. answer([B]) :- river(B) & exists B true amazon, amu_darya, amur, brahmaputra, colorado, congo_river, cubango, danube, don, elbe, euphrates, ganges, hwang_ho, indus, irrawaddy, lena, limpopo, mackenzie, mekong, mississippi, murray, niger_river, nile, ob, oder, orange, orinoco, parana, rhine, rhone, rio_grande, salween, senegal_river, tagus, vistula, volga, volta, yangtze, yenisei, yukon and zambesi. Reply: 0.166992sec.what countries are there in europe ?
Parse: 0.0500488sec. whq $VAR 1 s np 3+plu np_head int_det(B) [] country [] verb(be,active,pres+fin,[],pos) void pp prep(in) np 3+sin name(europe) [] Semantics: 0.032959sec. answer([B]) :- country(B) & in(B,europe) Planning: 0.0sec. answer([B]) :- in(B,europe) & {country(B)} albania, andorra, austria, belgium, bulgaria, cyprus, czechoslovakia, denmark, east_germany, eire, finland, france, greece, hungary, iceland, italy, liechtenstein, luxembourg, malta, monaco, netherlands, norway, poland, portugal, romania, san_marino, spain, sweden, switzerland, united_kingdom, west_germany and yugoslavia. Reply: 0.199951sec.
which is the largest african country ?
Parse: 0.0500488sec. whq $VAR 1 s np 3+sin wh(B) [] verb(be,active,pres+fin,[],pos) arg dir np 3+sin np_head det(the(sin)) sup most adj large adj african country [] [] Semantics: 0.0339356sec. answer([B]) :- exists C C = setof D:E country(E) & area(E,D) & african(E) & aggregate(max,C,B) Planning: 0.0500488sec. answer([B]) :- exists C C = setof D:E african(E) & {country(E)} & area(E,D) & aggregate(max,C,B) sudan. Reply: 0.300049sec.
what is the ocean that borders african countries and that borders asian countries ?
Parse: 0.0827637sec. whq $VAR 1 s np 3+sin wh(B) [] verb(be,active,pres+fin,[],pos) arg dir np 3+sin np_head det(the(sin)) [] ocean conj and rel $VAR 2 s np 3+sin wh(C) [] verb(border,active,pres+fin,[],pos) arg dir np 3+plu np_head generic adj african country [] [] rel $VAR 3 s np 3+sin wh(D) [] verb(border,active,pres+fin,[],pos) arg dir np 3+plu np_head generic adj asian country [] [] [] Semantics: 0.100098sec. answer([B]) :- ocean(B) & exists C country(C) & african(C) & borders(B,C) & exists D country(D) & asian(D) & borders(B,D) Planning: 0.0500488sec. answer([B]) :- exists C D ocean(B) & { borders(B,C) & {african(C)} & {country(C)} } & { borders(B,D) & {asian(D)} & {country(D)} } indian_ocean. Reply: 0.25sec.
how many countries does the danube flow through ?
Parse: 0.065918sec. whq $VAR 1 s np 3+sin name(danube) [] verb(flow,active,pres+fin,[],pos) [] pp prep(through) np 3+plu np_head quant(same,wh(B)) [] country [] Semantics: 0.0168457sec. answer([B]) :- B = numberof C country(C) & flows(danube,C) Planning: 0.0158691sec. answer([B]) :- B = numberof C flows(danube,C) & {country(C)} 6. Reply: 0.032959sec.
what is the total area of countries south of the equator and not in australasia ?
Parse: 0.0500488sec. whq $VAR 1 s np 3+sin wh(B) [] verb(be,active,pres+fin,[],pos) arg dir np 3+sin np_head det(the(sin)) adj total area pp prep(of) np 3+plu np_head generic [] country conj and reduced_rel $VAR 2 s np 3+plu wh(C) [] verb(be,active,pres+fin,[],pos) arg pred pp prep(southof) np 3+sin name(equator) [] [] reduced_rel $VAR 3 s np 3+plu wh(D) [] verb(be,active,pres+fin,[],neg) arg pred pp prep(in) np 3+sin name(australasia) [] [] [] Semantics: 0.132813sec. answer([B]) :- exists C C = setof D:[E] area(E,D) & country(E) & southof(E,equator) & \+in(E,australasia) & aggregate(total,C,B) Planning: 0.0830078sec. answer([B]) :- exists C C = setof D:[E] southof(E,equator) & area(E,D) & {country(E)} & {\+in(E,australasia)} & aggregate(total,C,B) 10228 ksqmiles. Reply: 0.25sec.
is there some ocean that does not border any country ?
Parse: 0.0500488sec. q s there verb(be,active,pres+fin,[],pos) arg dir np 3+sin np_head det(some) [] ocean rel $VAR 1 s np 3+sin wh(B) [] verb(border,active,pres+fin,[],neg) arg dir np 3+sin np_head det(any) [] country [] [] [] Semantics: 0.032959sec. answer([]) :- exists B ocean(B) & \+ exists C country(C) & borders(B,C) Planning: 0.032959sec. answer([]) :- exists B { ocean(B) & { \+ exists C borders(B,C) & {country(C)} } } Yes. Reply: 0.0158691sec.
what are the continents no country in which contains more than two cities whose population exceeds 1 million ?
Parse: 0.184082sec. whq $VAR 1 s np 3+plu wh(B) [] verb(be,active,pres+fin,[],pos) arg dir np 3+plu np_head det(the(plu)) [] continent rel $VAR 2 s np 3+sin np_head det(no) [] country pp prep(in) np 3+plu wh(C) [] verb(contain,active,pres+fin,[],pos) arg dir np 3+plu np_head quant(more,nb(2)) [] city rel $VAR 3 s np 3+sin np_head det(the(sin)) [] population pp poss np 3+plu wh(D) [] verb(exceed,active,pres+fin,[],pos) arg dir np 3+sin np_head quant(same,nb(1)) [] million [] [] [] [] Semantics: 0.0998535sec. answer([B]) :- B = setof C continent(C) & \+ exists D country(D) & in(D,C) & exists E E = numberof F city(F) & exists G population(F,G) & exceeds(G,1--million) & in(F,D) & E>2 Planning: 0.0500488sec. answer([B]) :- B = setof C continent(C) & \+ exists D country(D) & in(D,C) & exists E E = numberof F city(F) & exists G population(F,G) & exceeds(G,1--million) & in(F,D) & E>2 [africa,antarctica,australasia]. Reply: 25.0sec.
which country bordering the mediterranean borders a country that is bordered by a country whose population exceeds the population of india ?
Parse: 0.116943sec. whq $VAR 1 s np 3+sin np_head int_det(B) [] country reduced_rel $VAR 2 s np 3+sin wh(C) [] verb(border,active,inf,[prog],pos) arg dir np 3+sin name(mediterranean) [] [] verb(border,active,pres+fin,[],pos) arg dir np 3+sin np_head det(a) [] country rel $VAR 3 s np 3+sin wh(D) [] verb(border,passive,pres+fin,[],pos) [] pp prep(by) np 3+sin np_head det(a) [] country rel $VAR 4 s np 3+sin np_head det(the(sin)) [] population pp poss np 3+sin wh(E) [] verb(exceed,active,pres+fin,[],pos) arg dir np 3+sin np_head det(the(sin)) [] population pp prep(of) np 3+sin name(india) [] [] [] Semantics: 0.116943sec. answer([B]) :- country(B) & borders(B,mediterranean) & exists C country(C) & exists D country(D) & exists E population(D,E) & exists F population(india,F) & exceeds(E,F) & borders(D,C) & borders(B,C) Planning: 0.0830078sec. answer([B]) :- exists C D E F population(india,F) & borders(B,mediterranean) & {country(B)} & { borders(B,C) & {country(C)} & { borders(D,C) & {country(D)} & { population(D,E) & {exceeds(E,F)} } } } turkey. Reply: 1.09985sec.
which countries have a population exceeding 10 million ?
Parse: 0.0500488sec. whq $VAR 1 s np 3+plu np_head int_det(B) [] country [] verb(have,active,pres+fin,[],pos) arg dir np 3+sin np_head det(a) [] population reduced_rel $VAR 2 s np 3+sin wh(C) [] verb(exceed,active,inf,[prog],pos) arg dir np 3+plu np_head quant(same,nb(10)) [] million [] [] [] Semantics: 0.0671387sec. answer([B]) :- country(B) & exists C exceeds(C,10--million) & population(B,C) Planning: 0.0158691sec. answer([B]) :- exists C country(B) & { population(B,C) & {exceeds(C,10--million)} } afghanistan, algeria, argentina, australia, bangladesh, brazil, burma, canada, china, colombia, czechoslovakia, east_germany, egypt, ethiopia, france, india, indonesia, iran, italy, japan, kenya, mexico, morocco, nepal, netherlands, nigeria, north_korea, pakistan, peru, philippines, poland, south_africa, south_korea, soviet_union, spain, sri_lanka, sudan, taiwan, tanzania, thailand, turkey, united_kingdom, united_states, venezuela, vietnam, west_germany, yugoslavia and zaire. Reply: 0.466064sec.