1

As far as i understand, call_nth(:Goal, ?Nth) returns the Nth solution of Goal but at the same time it secretly calculates all the previous solutions (from 1st to (N-1)th) and simply ignores them. If we wish to compare the Xth with the (X+1)th solution for every X between 1 and N-1, call_nth becomes very costly, cause it basically keeps calculating solutions which have already been calculated in previous steps. I was wondering if there is a more efficient way to solve problems of this form, without using findall/3 of course.

(A typical example to this, would be the script below which finds the GOAL or the closest maximum to it, if GOAL doesn't exist in the predicates.)

num(10).
num(20).
num(30).
num(40).
num(50).

search_for_goal(GOAL,RESULT):-
    search_for_goal(GOAL,0,1,RESULT).

search_for_goal(GOAL,_,COUNTER,GOAL):-
    call_nth(num(GOAL),COUNTER),!.
search_for_goal(GOAL,CURRENT_MAX,COUNTER,RESULT):-
    call_nth(num(X),COUNTER),
    COUNTER2 is COUNTER+1,
    (  X=<CURRENT_MAX->
       search_for_goal(GOAL,CURRENT_MAX,COUNTER2,RESULT)
    ;  search_for_goal(GOAL,X,COUNTER2,RESULT)
    ).
search_for_goal(_,CURRENT_MAX,COUNTER,CURRENT_MAX):-
    \+call_nth(num(_),COUNTER).
false
  • 10,264
  • 13
  • 101
  • 209
TimzyPatzy
  • 95
  • 4
  • `As far as i understand, call_nth(:Goal, ?Nth) returns the Nth solution of Goal` Please read it again: `True when Goal succeeded for the Nth time.` – Guy Coder Apr 18 '19 at 23:26
  • Are you really interested in comparing **exactly** the Nth and N+1st answer? This is an extremely unusual thing to ask since the very precise order in which answers are produces is of relevance in only very rare cases - and in particular not in cases where you want to determine the maximum. – false Apr 19 '19 at 09:53
  • What is the problem you want to solve? `call_nth/2` has very specific uses, and most of the time it is called with an uninstantiated `Nth`. Not with a given `Nth`. This is **not** a predicate for beginners. – false Apr 19 '19 at 10:09
  • @false how could call_nth(GOAL, n) possibly know beforehand if the n-th solution exist? thus, i assume it calculates all the solutions through backtracking from 1 to n and simply returns the n-th one. My question is if there's a way, after getting the first solution, to "force" the system to jump immediately to the second solution, without recalculating the first solution - as call_nth(GOAL,2) would do. – TimzyPatzy Apr 19 '19 at 15:45
  • 1
    Let me repeat: What is the problem you want to solve? – false Apr 19 '19 at 15:55

1 Answers1

1

Using SWI-Prolog, this can be achieved with Prolog Engines. To illustrate this, consider my own version of the findall/3 predicate which returns only even-numbered solutions.

my_findall(Templ, Goal, List) :-
    setup_call_cleanup(
    engine_create(Templ, Goal, E),
    get_answers(E, List),
    engine_destroy(E)).

get_answers(E, [H|T]) :-
    /* Skip next solution. */
    engine_next(E, _),
    /* Take next solution. */
    engine_next(E, H),
    !,
    get_answers(E, T).

get_answers(_, []).

Querying with:

my_findall(X,member(X,[1,2,3,4]),Y)

Returns only the n'th solutions where n is even.

Y = [2, 4]
RobertBaron
  • 2,817
  • 1
  • 12
  • 19