Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SICStus Prolog: Find all solutions

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.

like image 498
Enigma Avatar asked Nov 27 '16 20:11

Enigma


1 Answers

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
like image 105
false Avatar answered Oct 13 '22 23:10

false