5
votes

Is there a way one can show all solutions and/or find how many there are in SICSTus prolog? For instance, the code below maybe used to solve the map colouring problem.

:- use_module(library(clpfd)). 
solve_AUSTRALIA(WA,NT,Q,SA,NSW,V):-
   domain([WA,NT,Q,SA,NSW,V], 1, 4),%colours represented by integers from 1 to 4
   WA #\= NT, 
   WA #\= SA, 
   NT #\= SA, 
   NT #\= Q, 
   SA #\= Q, 
   SA #\= NSW, 
   SA #\= V, 
   Q #\= NSW,
   NSW #\= V,
   labeling([],[WA,NT,Q,SA,NSW,V]).

At the moment,I am typing ; every time to see further solutions till Prolog says no. Is there a way I can tell prolog to show all solutions at once, or better, a way I can find how many there. Like prolog tells me there are five solutions to the problem.

1
You can try to use findall/3, findall/4, bagof/3 or setof/3. They are similar. For ex, what you want to do is put your solution predicate in findall(+Templagte, :Solution, -Bag), and original data set as Template, and collective solution as -Bag.RandomEli
A general tip for clpfd in SICStus: Say assert(clpfd:full_answer) at the toplevel to get the full answer including all constraints attached!false

1 Answers

5
votes

The following is for counting the number of answers. When you ask a query or execute a predicate, what you get back from Prolog are answers. Sometimes these answers are solutions, may contain more than one solution, infinitely many solutions, and sometimes even no solution at all.

The simplest way to go is to say findall(t, Goal_0, Ts), length(Ts, N). The only disadvantage is that this requires space proportional to the number of answers counted.

If you want to go one step further you need some kind of counter. Currently in SICStus 4.3.3 you can do this like so:

:- meta_predicate count_answers(0, ?).
:- meta_predicate count_answers1(0, +, ?). % internal

:- use_module(library(types),[must_be/4]).

:- use_module(library(structs),
         [new/2,
          dispose/1,
          get_contents/3,
          put_contents/3]).

count_answers(G_0, N) :-
   (  nonvar(N)
   -> must_be(N, integer, count_answers(G_0, N), 2)
   ;  true
   ),
   new(unsigned_64, Ref),
   call_cleanup(count_answers1(G_0, Ref, N), dispose(Ref) ).

count_answers1(G_0, Ref, N) :-
   (  call(G_0),
      get_contents(Ref, contents, N0),
      N1 is N0+1,
      put_contents(Ref, contents, N1),
      fail
   ;  get_contents(Ref, contents, N)
   ).

See this answer how counters can be implemented in other systems. Example use:

| ?- count_answers(member(_,"abcde"),Ans).
Ans = 5 ? ;
no