1% ===================================================================
    2% File 'logicmoo_util_engines.pl'
    3% Purpose: An Implementation in SWI-Prolog of Comparable context frames
    4% Maintainer: Douglas Miles
    5% Contact: $Author: dmiles $@users.sourceforge.net ;
    6% Version: 'logicmoo_util_ctx_frame.pl' 1.1.1
    7% Revision:  $Revision: 1.9 $
    8% Revised At:   $Date: 2035/12/16 01:57:18 $
    9% ===================================================================
   10% ===================================================================
   11%  
   12%   Run multiple goals (in separate thread/engines)
   13%
   14               
   15:- module(logicmoo_util_engines,
   16  [ result_check/3,
   17    on_diff_fail/2,
   18    on_diff_throw/2,
   19    call_diff/3,
   20    intersect_eq0/3,
   21   % member_eq0/2,
   22    collecting_list/4,
   23
   24    start_listening/1,
   25    call_in_engine/1,
   26    start_goal_saved1/0,
   27    wait_until_next_request/0,
   28    next_solution/0,
   29    next_solution/1
   30  ]).   31
   32:- meta_predicate
   33   collecting_list(0,+,+,+),
   34   result_check(0,+,+),
   35   call_in_engine(0),
   36   on_diff_throw(0,0),
   37   on_diff_fail(0,0),
   38   call_diff(2,0,0).   39   
   40   
   41
   42result_check(Call, _ + NVs, _ + OVs):-
   43   NVs=@=OVs -> true; Call.
   44
   45
   46/*
   47
   48  % I'd like these two to run at the same time (Did I really 
   49  need to start a thread with send_messages)
   50 
   51 ?- on_diff_fail(member(X,[1,2,3,4]),member(X,[1,2,x,4])). 
   52   X = 1 ;
   53   X = 2 ;
   54   X = 4 ;
   55   No.
   56*/
   57
   58on_diff_fail(Left,Right):- 
   59  call_diff(result_check(fail),Left,Right).
   60
   61on_diff_throw(Left,Right):- 
   62  call_diff(result_check(trace_or_throw(different(Left,Right))),Left,Right).
   63
   64call_diff(Check,Left,Right):- 
   65   shared_vars(Left,Right,Vs),
   66 % Right must be able to diverge
   67   copy_term(Right+Vs,CO+CVs),
   68 % Later on we''ll allow different result orders
   69   NOL = saved_in([],[]), 
   70   collecting_list(call(CO),CVs,1,NOL),
   71   collecting_list(call(Left),Vs,2,NOL),
   72   call(Check,Left+Vs,Right+CVs).
   73
   74collecting_list(G,Vs,At,S):- 
   75   call(G),copy_term(Vs,CVs),
   76   arg(At,S,Was),nb_setarg(At,S,[CVs|Was]).
   77
   78
   79:- thread_initialization(nb_setval(query_result,sol(0,1,false,false))).   80
   81% sol(number,G,successfull,done)
   82next_solution:- quietly(next_solution(How)),call(How).
   83
   84next_solution(throw(no_query_result)) :- \+ nb_current(query_result,_),!.
   85next_solution(request_next0) :- nb_getval(query_result,sol(_,_,true,false)),!.
   86next_solution(nop(last(G))) :- nb_getval(query_result,sol(_,G,true,true)),!.
   87next_solution(request_next0) :- nb_getval(query_result,sol(_,_,_,false)),!.
   88next_solution(nop(unknown(QR))) :- nb_getval(query_result,QR),!.
   89
   90request_next0 :- 
   91  quietly((thread_send_message(ask1,please(next_sol)), !, 
   92  thread_get_message(answer1,M),wdmsg(rn(M)),nb_setval(query_result,M))),!.
   93
   94call_in_engine(G):- 
   95  once((nb_setval(in,v(_,G,_)), 
   96    start_goal_saved1)),fail.
   97call_in_engine(G):- next_solution, get_sol(G).
   98
   99
  100get_sol(G):-
  101  repeat,
  102  next_solution,
  103  nb_getval(query_result,M),
  104  react_message(M,G,(ReactA,ReactB)),
  105  wdmsg(M),
  106  (ReactA == ! -> ! ; ReactA),
  107   ReactB.
  108
  109react_message(sol(_,_,unknown,false),_,(true,fail)):-!.
  110react_message(sol(_,_,false,_),_,(!,fail)):- !.
  111react_message(sol(_,G,true,false),G,(true,true)):-!.
  112react_message(sol(_,G,true,true),G,(!,true)):- !.
  113
  114
  115call_goal_in_thread_saved_nd:- start_goal_saved1, fail.
  116call_goal_in_thread_saved_nd:- next_solution.
  117
  118:-  message_queue_property(_Queue, alias(answer1)) -> true;message_queue_create(_,[alias(answer1)]).  119:-  message_queue_property(_Queue, alias(ask1)) -> true;message_queue_create(_,[alias(ask1)]).  120
  121
  122start_goal_saved1:- 
  123  quietly((nb_getval(in,v(_,G,_,_)),
  124  thread_create(start_listening(G),_ID,[detached(true)]))),
  125  nb_setval(query_result,sol(0,G,unknown,false)),!.
  126
  127wait_until_next_request:-
  128   thread_get_message(ask1,please(C),[]),
  129   (C == more_sols -> true; (C == completed -> (!,fail) ; (true))).
  130
  131thread_send_answer(Left,G,TF,Done):- wdmsg(next_________sol(Left,G,TF,Done)), thread_send_message(answer1,sol(Left,G,TF,Done)).
  132
  133:- meta_predicate start_listening(0).  134start_listening(G):-
  135  quietly((flag(sol,_,0),
  136  ((thread_send_answer(0,G,unknown,false)),
  137  thread_get_message(ask1,please(next_sol),[]),  
  138  ignore(((
  139  ((G,deterministic(Det),flag(sol,I,I+1))
  140    *-> (flag(sol,X,X),thread_send_answer(X,G,true,Det),wait_until_next_request) ; 
  141    flag(sol,X,X),thread_send_answer(X,G,false,true))
  142    ),fail))))).
  143  
  144
  145intersect_eq0([], _, []).
  146intersect_eq0([X|Xs], Ys, L) :-
  147 	(   member_eq0(X, Ys)
  148 	->  L = [X|T],
  149 	    intersect_eq0(Xs, Ys, T)
  150 	;   intersect_eq0(Xs, Ys, L)
  151 	)