I am trying to find how to find the number of solutions in a script. my current script is:
ksol(K,ST) :- length(L1,K), maketemplate(L1,ST,K), kset(Kset,K),
asserta( (qn(K))),asserta( (st(ST))), asserta( (kset(Kset)) ).
% number of queens, solution template
maketemplate([],[],_K).
maketemplate([X|Rest],[N1/X|RT],K) :- maketemplate(Rest,RT,K),
length([X|Rest],N),N1 is K-N+1,!.
kset([],0).
kset([N|Rest],N) :-N1 is N-1, kset(Rest,N1),!.
solution(L) :- st(L), sol(L).
sol([8]).
sol([Q|Queens]) :- sol(Queens),
Q=_X/Y, kset(Kset),member(Y,Kset),
noattack(Q,Queens).
more specifically, within this script, I am trying to see how many solutions are generated by prolog for 8 queens.
would anyone be able to help me with this?
Using assert/retract to count the number of successful goal calls is rather inefficient and error prone.
In SWI-Prolog, the easier solution is aggregate_all/3, available from the preloaded library(aggregate).
I'm not sure about which goal you want to count, assuming it's solution/1, you should use
?- aggregate_all(count,solution(_),N).
In Prolog dialects where library(aggregate) is not available, the easier way should be
?- findall(t,solution(_),L),length(L,N).
Related
So in the tag prolog someone wanted to solve the "the giant cat army riddle" by Dan Finkel (see video / Link for description of the puzzle).
Since I want to improve in answer set programming I hereby challenge you to solve the puzzle more efficient than me. You will find my solution as answer. I'll accept the fastest running answer (except if it's using dirty hacks).
Rules:
hardcoding the length of the list (or something similar) counts as dirty hack.
The output has to be in the predicate r/2, where it's first argument is the index of the list and the second its entry.
Time measured is for the first valid answer.
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
% no need to add operations that start with 14
op(Ori,New):- num(Ori), New = Ori+7, num(New), Ori!=14.
op(Ori,New):- num(Ori), New = Ori+5, num(New), Ori!=14.
%iteratively create new numbers from old numbers
l(0,0).
{l(T+1,New) : op(Old,New)} = 1 :- l(T,Old), num(T+1), op(Old,_).
%no number twice
:- 2 #sum {1,T : l(T,Value)}, num(Value).
%2 before 10 before 14
%linear encoding
reached(T,10) :- l(T,10).
reached(T+1,10) :- reached(T,10), num(T+1).
:- reached(T,10), l(T,2).
:- l(T,14), l(T+1,_).
%looks nicer, but quadratic
%:- l(T2,2), l(T10,10), T10<T2.
%:- l(T14,14), l(T10,10), T14<T10.
%we must have these three numbers in the list somewhere
:- not l(_,2).
:- not l(_,10).
:- not l(_,14).
#show r(T,V) : l(T,V).
#show.
Having a slightly more ugly encoding improves grounding a lot (which was your main problem).
I restricted op/2 to not start with 14, as this should be the last element in the list
I do create the list iteratively, this may not be as nice, but at least for the start of the list it already removed impossible to reach values via grounding. So you will never have l(1,33) or l(2,45) etc...
Also list generation stops when reaching the value 14, as no more operation is possible/needed.
I also added a linear scaling version of the "before" section, although it is not really necessary for this short list (but a cool trick in general if you have long lists!) This is called "chaining".
Also note that your show statement is non-trivial and does create some constraints/variables.
I hope this helps, otherwise feel free to ask such questions also on our potassco mailing list ;)
My first attempt is to generate a permutation of numbers and force successor elements to be connected by one of the 3 operations (+5, +7 or sqrt). I predefine the operations to avoid choosing/counting problems. Testing for <60 is not necessary since the output of an operation has to be a number between 0 and 59. The generated List l/2 is forwarded to the output r/2 until the number 14 appears. I guess there is plenty of room to outrun my solution.
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
op(Ori,New):- num(Ori), New = Ori+7, num(New).
op(Ori,New):- num(Ori), New = Ori+5, num(New).
%for each position one number
l(0,0).
{l(T,N):num(N)}==1:-num(T).
{l(T,N):num(T)}==1:-num(N).
% following numbers are connected with an operation until 14
:- l(T,Ori), not op(Ori,New), l(T+1,New), l(End,14), T+1<=End.
% 2 before 10 before 14
:- l(T2,2), l(T10,10), T10<T2.
:- l(T14,14), l(T10,10), T14<T10.
% output
r(T,E):- l(T,E), l(End,14), T<=End.
#show r/2.
first Answer:
r(0,0) r(1,5) r(2,12) r(3,19) r(4,26) r(5,31) r(6,36) r(7,6)
r(8,11) r(9,16) r(10,4) r(11,2) r(12,9) r(13,3) r(14,10) r(15,15)
r(16,20) r(17,25) r(18,30) r(19,37) r(20,42) r(21,49) r(22,7) r(23,14)
There are multiple possible lists with different length.
I'm unable to figure out why my code isn't working despite looking through answers to similar questions. I'm too new at Prolog to properly name things, but I hope you can see what I'm trying to get at.
I am defining a timetable roughly based on this program and am struggling with getting a list of the Classes that Mike teaches for a given result (Next step will be to declare that only results where both Mike and Phil teach 2 should be returned, but I want to work through it so that I can see and understand what's going on).
I imagine this should be simple but any combinations of the addToList(List,C) predicate never work. I know there is the append predicate but I hear it's inefficient, and would like to learn the 'raw' way. I don't know how many variations I've attempted and can't get my head around the way Prolog works in this regard and don't know on what level I'm going wrong - it's all a bit of a black box mystery working with it.
var program =
:- use_module(library(lists)).
prefers(may,a).
prefers(may,b).
prefers(may,c).
prefers(may,d).
prefers(bob,a).
prefers(bob,b).
prefers(bob,c).
prefers(pete,a).
prefers(pete,b).
prefers(pete,c).
prefers(pete,d).
prefers(tom,a).
prefers(tom,b).
prefers(tom,c).
prefers(tom,d).
teacher_pref(mike,a).
teacher_pref(mike,b).
teacher_pref(mike,c).
teacher_pref(phil,b).
teacher_pref(phil,c).
teacher_pref(phil,d).
addToList([C|List],C):- addToList(List,C).
timetable([a,[C1,S1,T1],b,[C2,S2,T2],c,[C3,S3,T3],d,[C4,S4,T4]],List1):-
teacher_pref(T1,C1),
teacher_pref(T2,C2),
teacher_pref(T3,C3),
teacher_pref(T4,C4),
prefers(S1,C1),
prefers(S2,C2),
S1\\=S2,
prefers(S3,C3),
S1\\=S3,
S2\\=S3,
prefers(S4,C4),
S1\\=S4,
S2\\=S4,
S3\\=S4,
addToList(List1,C):-
teacher_pref(mike,C).
session.consult( program );
session.query('timetable([C1,[a,S1,T1],C2,[b,S2,T2],C3,[c,S3,T3,L3],C4,[d,S4,T4]],List1).')
If I understand correctly you have:
teacher_pref(mike,a).
teacher_pref(mike,b).
teacher_pref(mike,c).
And you want to get a list of these classes, which would be:
[a, b, c]
In Prolog we have some higher-order predicates that are for occasions like this:
% (What to find, the goal to call, all the results)
?- findall(Class, teacher_pref(mike, Class), Classes).
Classes = [a, b, c].
In the Tau-Prolog docs they're under All Solutions, in SWI-Prolog there's a couple more.
To make this into a more generic predicate:
teacher_prefs(Teacher, Prefs) :-
findall(Pref, teacher_pref(Teacher, Pref), Prefs).
I have an array L of some type, I'm trying to extract the data to an array, for example:
L=[day(sunday),day(monday)]
to
Target=[sunday,monday]
Tried using forall and searched for related questions on Prolog lists.
extract_data_to_list(L,Target) :-
member(day(Day),L),
length(L, L1),
length(Target, L1),
member(Day,Target).
Current output:
?- extract_data_to_list([day(sunday),day(monday)],Target).
Target = [sunday, _5448] ;
Target = [_5442, sunday] ;
Target = [monday, _5448] ;
Target = [_5442, monday].
Desired output:
?- extract_data_to_list([day(sunday),day(monday)],Target).
Target=[sunday,monday]
This is an ideal problem for maplist:
day_name(day(DayName), DayName).
dates_daylist(Dates, DayList) :-
maplist(day_name, Dates, DayList).
Maplist applies day_name to each corresponding pair of elements in Dates and DayList.
This is an ideal problem for library(lambda) for SICStus|SWI:
maplist(\day(N)^N^true, Dates, Daylist).
I have a couple other ways you can do this, just in case you're wondering.
?- findall(D, member(day(D), [day(monday), day(tuesday)]), Days).
Days = [monday, tuesday].
The trick here is that you can use findall/3 to drive a simple loop, if the Goal (argument 2) uses member/2. In this case, we're unifying day(D) with each item in the list; no further work really needs to happen besides the unification, so we're able to "tear off the wrapping" just with member/2 but you could drive a more complex loop here by parenthesizing the arguments. Suppose you wanted to change day to day-of-week, for instance:
?- findall(DoW, (member(day(D),
[day(monday), day(tuesday)]), DoW=day_of_week(D)),
Days).
Days = [day_of_week(monday), day_of_week(tuesday)].
Making the goal more complex works, in other words, as long as you parenthesize it.
The second trick is specific to SWI-Prolog (or Logtalk, if you can use that), which is the new library(yall):
?- maplist([Wrapped,Day]>>(Wrapped=day(Day)),
[day(monday),day(tuesday)], X).
X = [monday, tuesday].
library(yall) enables you to write anonymous predicates. [Wrapped,Day]>>(Wrapped=day(Day)) is sort of like an inline predicate, doing here exactly what #lurker's day_name/2 predicate is doing, except right inside the maplist/3 call itself without needing to be a separate predicate. The general syntax looks something like [Variables...]>>Goal. This sort of thing was previously available as library(lambda) and has been a feature of Logtalk for many years.
I'm struggling with my project in Prolog. My problem is, given a file containing the traffic lines in the form of line(NameOfLine, Type, ListOfStations). For example:
line(m1, train, [a,b,c,d,e])
line(m2, train, [h,e,j,i])
...
where e is the intersecting station of two line (The real line file is very complicated and containing a dozen of lines with hundreds of stations). I have to do the classic graph question like find a routing, calculate the cost, etc.
I knew that I have to build a graph undirected before start, so I've tried something like this:
adjacent(X,Y,[X,Y|_]).
adjacent(X,Y,[_|T]) :- adjacent(X,Y,T).
find_edge(LArret) :- forall(adjacent(X, Y, LArret), assert(edge(X,Y))).
connected(X,Y) :- edge(X,Y) ; edge(Y,X).
graph :-
forall(ligne(_,_,L), find_edge(L)).
But I didn't get all the edges as expected. Can you guys give me some advice for that? Or was I wrong at very first for solving this kind of problem?
Supplementary question:
Thanks for the solution proposed and i've finally succeed to define the edges. Then i tried this algorithm classic to find a path betwwen A and B, but sometimes the search doesn't seem to end and sometimes the program stuck in searching.
connected(X,Y) :- edge(X,Y) ; edge(Y,X).
path(A,B,Path) :-
travel(A,B,[A],Q),
reverse(Q,Path).
travel(A,B,P,[B|P]) :-
connected(A,B).
travel(A,B,Visited,Path) :-
connected(A,C),
C \== B,
\+member(C,Visited),
travel(C,B,[C|Visited],Path).
I think the reason could be a loop in the graph or a infinite loop in seraching, how can I avoid this kind of problem but still find all the path possible?
I was able to use the following code with your line/3 definitions to create your list of edge/2 definitions:
adjacent(X,Y, [X,Y|_]).
adjacent(X,Y, [_|T]) :- adjacent(X,Y, T).
adjacent_lines(X,Y) :- line(_,_,L), adjacent(X,Y, L).
:- forall(adjacent_lines(X, Y), assert(edge(X, Y))).
It created all applicable and valid edge/2 facts as specified by the line/3 facts.
(at least, with SWI-Prolog)
I have three types of facts:
album(code, artist, title, date).
songs(code, songlist).
musicians(code, list).
Example:
album(123, 'Rolling Stones', 'Beggars Banquet', 1968).
songs(123, ['Sympathy for the Devil', 'Street Fighting Man']).
musicians(123, [[vocals, 'Mick Jagger'], [guitar, 'Keith Richards', 'Brian Jones']].
I need to create these 4 rules:
together(X,Y) This succeeds if X and Y have played on the same album.
artistchain(X,Y) This succeeds if a chain of albums exists from X to Y;
two musicians are linked in the chain by 'together'.
role(X,Y) This succeeds if X had role Y (e.g. guitar) ever.
song(X,Y) This succeeds if artist X recorded song Y.
Any help?
I haven't been able to come up with much but for role(X,Y) I came up with:
role(X,Y) :- prole(X,Y,musicians(_,W)).
prole(X,Y,[[Y|[X|T]]|Z]).
prole(X,Y,[[Y|[H|T]]|Z]) :- prole(X,Y,[[Y|T]|Z]).
prole(X,Y,[A|Z]) :- prole(X,Y,Z).
But that doesn't work. It does work if I manually put in a list instead of musicians(_,W) like [[1,2,3],[4,5,6]].
Is there another way for me to insert the list as a variable?
As for the other rules I'm at a complete loss. Any help would really be appreciated.
You have a misconception about Prolog: Answering a goal in Prolog is not the same as calling a function!
E.g.: You expect that when "role(X,Y) :- prole(X,Y,musicians(_,W))." is executed, "musicians(_,W)" will be evaluated, because it is an argument to "prole". This is not how Prolog works. At each step, it attempts to unify the goal with a stored predicate, and all arguments are treaded either as variables or grounded terms.
The correct way to do it is:
role(X,Y) :- musicians(_, L), prole(X,Y,L).
The first goal unifies L with a list of musicians, and the second goal finds the role (assuming that the rest of your code is correct).
Little Bobby Tables is right, you need to understand the declarative style of Prolog. Your aim is to provide a set of rules that will match against the set of facts in the database.
Very simply, imagine that I have the following database
guitarist(keith).
guitarist(jim).
in_band('Rolling Stones', keith).
in_band('Rolling Stones', mick).
Supposed I want to find out who is both a guitarist and in the Rolling Stones. I could use a rule like this
stones_guitarist(X):-
guitarist(X),
in_band('Rolling Stones', X).
When a variable name is given within a rule (in this case X) it holds its value during the rule, so what we're saying is that the X which is a guitarist must also be the same X that is in a band called 'Rolling Stones'.
There are lots of possible ways for you to arrange the database. For example it might be easier if the names of the musicians were themselves a list (e.g. [guitar,[keith,brian]]).
I hope the following example for song(X,Y) is of some help. I'm using Sicstus Prolog so import the lists library to get 'member', but if you don't have that it's fairly easy to make it yourself.
:- use_module(library(lists)).
song(ARTIST,SONG):-
album(CODE,ARTIST,_,_),
songs(CODE,TRACKS),
member(SONG,TRACKS).