:-module solve_sys.
:-with_macro pimos.
:-public solve_system/4,head_unify/3,var/2,functor/4,reduce/4,
%unify_1/2,
reflect/1.



solve_system(functor(G,F,A),T,NT,Sync):-
  true|
  functor(G,F,A,Res),
  solve_system2(Res,functor(G,F,A),T,NT,Sync).

solve_system(ad(X,A,B),T,NT,Sync):-
  true|
  ':='(X,'+',A,B,Res),
  solve_system2(Res,ad(X,A,B),T,NT,Sync).
 
solve_system((X<Y),T,NT,Sync):-
  true|
  '<'(X,Y,Res),
  solve_system2(Res,(X<Y),T,NT,Sync).

solve_system((X\=Y),T,NT,Sync):-
  true|
  unify(X,Y,Res1),
  not_unify(Res1,Res),
  solve_system2(Res,(X\=Y),T,NT,Sync).

solve_system((X=Y),T,NT,Sync):-
  true|
  unify(X,Y,Res),
  solve_system2(Res,(X=Y),T,NT,Sync).

solve_system(sys((X=Y)),T,NT,Sync):-
  true|
  unify(X,Y,Res),
  solve_system2(Res,(X=Y),T,NT,Sync).

solve_system(true,T,NT,Sync):-
  true|
  solve_system2(success,true,T,NT,Sync).

solve_system(merge(S1,S2,S),T,NT,Sync):-
  true|
  merge(S1,S2,S,T,NT),
  solve_system2(procsuccess,merge(S1,S2,S),T,NT,Sync).

solve_system(and(S1,S2,S),T,NT,Sync):-
  true|
  and(S1,S2,S,T,NT),
  solve_system2(procsuccess,and(S1,S2,S),T,NT,Sync).

solve_system(exec(I,O,H,T0,RC,MRC),T,NT,Sync):-
  true|
  exec(I,O,H,T0,RC,MRC,T,NT),
  solve_system2(procsuccess,exec(I,O,H,T0,RC,MRC),T,NT,Sync).

solve_system(exec(EH,ET,I,O,H,T0,RC,MRC),T,NT,Sync):-
  true|
  exec(EH,ET,I,O,H,T0,RC,MRC,T,NT),
  solve_system2(procsuccess,exec(EH,ET,I,O,H,T0,RC,MRC),T,NT,Sync).

solve_system(exec_susp(I,O,H,T0,RC,MRC),T,NT,Sync):-
  true|
  exec_susp(I,O,H,T0,RC,MRC,T,NT),
  solve_system2(procsuccess,exec(I,O,H,T0,RC,MRC),T,NT,Sync).

solve_system(sum_q(Q,N),T,NT,Sync):-
  true|
  sum_q(Q,N),
  solve_system2(success,sum_q(Q,N),T,NT,Sync).

solve_system(throw(N,Q,T1,NQ,NT1),T,NT,Sync):-
  true|
  throw(N,Q,T1,NQ,NT1),
  solve_system2(success,throw(N,Q,T1,NQ,NT1),T,NT,Sync).


solve_system2(procsuccess,G,T,NT,Sync):-
  true|
  Sync=go.

solve_system2(success,G,T,NT,Sync):-
  true|
  T=NT,
  Sync=go.

solve_system2(fail,G,T,NT,Sync):-
  true|
  T=[failure(G)|NT],
  Sync=go.

solve_system2(suspend,G,T,NT,Sync):-
  true|
  T=[G|NT],
  Sync=go.



not_unify(success,Fail):-
  true|
  Fail=fail.

not_unify(fail,Success):-
  true|
  Success=success.

not_unify(suspend,Suspend):-
  true|
  Suspend=suspend.



functor(G,F,A,Res):-
  true|
  functor(G,(_,F,A,Res)).

functor(A,B):- 
  atom(A)|
  B=(atom,A,0,success).

functor(A,B):-
  vector(A)|
  vector(A,S,Av),
  Size:=S-1,
  vector_element(Av,0,Functor,_),
  B=(vector,Functor,Size,success).

otherwise.
functor(A,B):-
  true|
  unbound(A,C),
  functor2(A,C,B).


functor2(A,B,C):-
  {A}=B|
  C=(_,_,_,fail).

otherwise.
functor2(A,B,C):-
  true|
  C=(_,_,_,suspend).



merge(S1,S2,L,T,NT):-
  true|
  unbound(S1,S1V),
  unbound(S2,S2V),
  merge1(S1V,S2V,S1,S2,L,T,NT).


merge1({_,_,_},{_,_,_},S1,S2,L,T,NT):-
  true|
  T=[merge(S1,S2,L)|NT].

otherwise.
merge1(_,_,S1,S2,L,T,NT):-
  true|merge2(S1,S2,L,T,NT).


merge2(S1,S2,L,T,NT):-
  S1=[S|S1T]|
  L=[S|L1],
  T=[merge(S2,S1T,L1)|NT].

merge2(S1,S2,L,T,NT):-
  S2=[S|S2T]|
  L=[S|L1],
  T=[merge(S2T,S1,L1)|NT].

merge2(S1,S2,L,T,NT):-
  S1=[]| 
  L=S2,
  T=NT.

merge2(S1,S2,L,T,NT):-
  S2=[]|
  L=S1,
  T=NT.



and(O1,O2,Output,T,NT):-
  true|
  unbound(O1,O1V),
  unbound(O2,O2V),
  and(O1V,O2V,O1,O2,Output,T,NT).

and({_,_,_},{_,_,_},O1,O2,Output,T,NT):-
  true|
  T=[and(O1,O2,Output)|NT].

otherwise.
and(_,_,O1,O2,Output,T,NT):-
  true|
  and_0(O1,O2,Output,T,NT).


and_0([H1|T1],O2,Output,T,NT):-
  true|
  and_1([H1|T1],O2,Output,T,NT).

and_0(O1,[H1|T1],Output,T,NT):-
  true|
  and_1([H1|T1],O1,Output,T,NT).


and_1([success|_],O2,Output,T,NT):-
  true|
  O2=Output,
  T=NT.

and_1([failure(G)|_],O2,Output,T,NT):-
  true|
  Output=[failure(G)],
  T=NT.

and_1([aborted|_],O2,Output,T,NT):-
  true|
  O2=Output,
  T=NT.

and_1([],O2,Output,T,NT):-
  true|
  O2=Output,
  T=NT.

otherwise.
and_1([G|O1],O2,Output,T,NT):-
  true|
  Output=[G|Output1],
  T=[and(O2,O1,Output1)|NT].

            

end(In,Out,['$$$'|Q],QT,RC,MRC,Tail,NTail):-
  true|
  Out=[success],
  Tail=NTail.

otherwise.
end(In,Out,Q,QT,RC,MRC,Tail,NTail):-
  true|
  exec(In,Out,Q,QT,RC,MRC,Tail,NTail).



exec(In,Out,H,T,RC,MRC,Tail,NTail):-
  In=[C|In1]|
  exec_control(C,In1,Out,H,T,RC,MRC,Tail,NTail).

exec(In,Out,['$$$'|H],T,RC,MRC,Tail,NTail):-
  true|
  T=['$$$'|NT],
  end(In,Out,H,NT,RC,MRC,Tail,NTail).

exec(In,Out,H,T,RC,MRC,Tail,NTail):-
  RC=MRC|
  Out=[over_count|Out1],
 Tail=NTail.

exec(In,Out,[G|H],T,RC,MRC,Tail,NTail):-
  G\='$$$'|
  Sys=(_,_,_,_),
  sys(G,Sys),
  exec1(Sys,In,Out,[G|H],T,RC,MRC,Tail,NTail).


exec1(Sys,In,Out,[bt(create(G),reflect)|H],T,RC,MRC,Tail,NTail):-
  true|
  Out=[bt(create(G,MRC,NG),reflect)|Out1],
  T=[NG|NT],
  Tail=[exec(In,Out1,H,NT,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(create(G,D1,D2,XX,YY),reflect)|H],T,RC,MRC,Tail,NTail):-
  true|
  D2=NG,
  Out=[bt(create(G,MRC,NG,XX,YY),reflect)|Out1],
  T=[NG|NT],
  Tail=[exec(In,Out1,H,NT,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(link_channel2(G1,C,G2),reflect)|H],T,RC,MRC,Tail,NTail):-
  true|
  Out=[link_channel2(create(G1,MRC,NG1),C,bt(create(G2,MRC,NG2)),reflect)|Out1],
  T=[NG1,NG2|NT],
  Tail=[exec(In,Out1,H,NT,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(link_channel1(G,C,M),reflect)|H],T,RC,MRC,Tail,NTail):-
  true|
  Out=[link_channel1(bt(create(G,MRC,NG),C,M),reflect)|Out1],
  T=[NG|NT],
  Tail=[exec(In,Out1,H,NT,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(G,P)|H],T,RC,MRC,Tail,NTail):-
  P=exp|
  Tail=[exec([G|ET],ET,In,Out,H,T,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(G,P)|H],T,RC,MRC,Tail,NTail):-
  P=io|
  Out=[bt(G,P)|Out1],
  Tail=[exec(In,Out1,H,T,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(G,P)|H],T,RC,MRC,Tail,NTail):-
  P=reflect|
  Out=[bt(G,P)|Out1],
  Tail=[exec(In,Out1,H,T,RC,MRC)|NTail].

exec1(Sys,In,Out,[bt(G,P)|H],T,RC,MRC,Tail,NTail):-
  P\=exp,
  P\=io,
  P\=reflect|
  Out=[goal(bt(G,P),MRC)|Out1],
  Tail=[exec(In,Out1,H,T,RC,MRC)|NTail].

exec1(Sys,In,Out,[merge(S1,S2,S)|H],T,RC,MRC,Tail,NTail):-
  true|
  merge(S1,S2,S,T,NT),
  Tail=[exec(In,Out,H,NT,RC,MRC)|NTail].

exec1(Sys,In,Out,[G|H],T,RC,MRC,Tail,NTail):-
  Sys=(_,_,false,_)|
  reduce(G,T,NT,RC,RC1,Out,Out1,Sync),
  Tail=[exec(In,Out1,H,NT,RC1,MRC)|NTail].

exec1(Sys,In,Out,[G|H],T,RC,MRC,Tail,NTail):-
  Sys=(_,_,true,_)|    
  solve_system(G,T,NT,RC,RC1,Out,Out1),
  Tail=[exec(In,Out1,H,NT,RC1,MRC)|NTail].

exec1(Sys,In,Out,[true|H],T,RC,MRC,Tail,NTail):-
  true|
  Tail=[exec(In,Out,H,T,RC,MRC)|NTail].

exec1(Sys,In,Out,[false|H],T,RC,MRC,Tail,NTail):-
  true|
  Out=[failure(false)|_],
  Tail=NTail.

otherwise.
exec1(Sys,In,Out,[G|H],T,RC,MRC,Tail,NTail):-
  true|
  T=[G|NT],
  Tail=[exec(In,Out,H,NT,RC,MRC)|NTail].


exec_susp(In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  unbound(In,INV),
  exec_susp1(INV,In,Out,H,T,RC,MRC,Tail,NTail).

exec_susp1({_,_,_},In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Tail=[exec_susp(In,Out,H,T,RC,MRC)|NTail].

exec_susp1({_},[resume|In],Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Tail=[exec(In,Out,H,T,RC,MRC)|NTail]. 

exec_susp1({_},[abort|In],Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Out=[],
  Tail=NTail.





exec_control(halt,In,Out,H,T,RCC,MRC,Tail,NTail):-
  true|
  Out=[],
  Tail=NTail.

exec_control(suspend,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Tail=[exec_susp(In,Out,H,T,RC,MRC)|NTail].

exec_control(abort,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Out=[],
  Tail=NTail.

solve_system(ad(X,A,B),T,NT,RC,RC1,Out,Out2):-
  true|
  ':='(X,'+',A,B,Res),
  solve_system2(Res,ad(X,A,B),T,NT,RC,RC1,Out,Out2).

solve_system(sb(X,A,B),T,NT,RC,RC1,Out,Out2):-
  true|
  ':='(X,'-',A,B,Res),
  solve_system2(Res,ad(X,A,B),T,NT,RC,RC1,Out,Out2).

solve_system(mt(X,A,B),T,NT,RC,RC1,Out,Out2):-
  true|
  ':='(X,'*',A,B,Res),
  solve_system2(Res,mt(X,A,B),T,NT,RC,RC1,Out,Out2).

solve_system((X<Y),T,NT,RC,RC1,Out,Out2):-
  true|
  '<'(X,Y,Res),
  solve_system2(Res,(X<Y),T,NT,RC,RC1,Out,Out2).

solve_system((X=Y),T,NT,RC,RC1,Out,Out2):-
  true|
  unify(X,Y,Res),
  solve_system2(Res,(X=Y),T,NT,RC,RC1,Out,Out2).

solve_system(true,T,NT,RC,RC1,Out,Out2):-
  true|
  solve_system2(success,true,T,NT,RC,RC1,Out,Out2).

solve_system(merge(S1,S2,S),T,NT,RC,RC1,Out,Out2):-
  merge(S1,S2,S,T,NT),
  solve_system2(procsuccess,merge(S1,S2,S),T,NT,RC,RC1,Out,Out2).

solve_system(and(S1,S2,S),T,NT,RC,RC1,Out,Out2):-
  true|
  and(S1,S2,S,T,NT),
  solve_system2(procsuccess,and(S1,S2,S),T,NT,RC,RC1,Out,Out2).

solve_system(exec(I,O,H,T0,RC00,RC01),T,NT,RC,RC1,Out,Out2):-
  true|
  exec(I,O,H,T0,RC00,RC01,T,NT),
  solve_system2(procsuccess,exec(I,O,H,T0,RC00,RC01),T,NT,RC,RC1,Out,Out2).

solve_system(exec(EH,ET,I,O,H,T0,RC00,RC01),T,NT,RC,RC1,Out,Out2):-
  true|
  exec(EH,ET,I,O,H,T0,RC00,RC01,T,NT),
  solve_system2(procsuccess,exec(EH,ET,I,O,H,T0,RC00,RC01),T,NT,RC,RC1,Out,Out2).

solve_system(delay,T,NT,RC,RC1,Out,Out2):-
  true|
  solve_system2(success,delay,T,NT,RC,RC1,Out,Out2).
    

solve_system2(procsuccess,G,T,NT,RC,RC1,Out,Out2):-
  true|
  Out2=Out,
  RC1:= RC+1.

solve_system2(success,G,T,NT,RC,RC1,Out,Out2):-
  true|
  Out2=Out,
  T=NT,
  RC1:=RC+1.

solve_system2(fail,G,T,NT,RC,RC1,Out,Out2):-
  true|
  Out3=Out2,
  Out=[failure(G)|Out3].

solve_system2(suspend,G,T,NT,RC,RC1,Out,Out2):-
  true|
  T=[G|NT],
  RC=RC1,
  Out=Out2.



reduce(Goal,T,NT,RC,RC1,Out,Out1,Sync):-
  true|
  clauses(Goal,Clauses),
  reduce2(Clauses,Goal,T,NT,RC,RC1,Out,Out1,Sync).


reduce2(Clauses,Goal,T,NT,RC,RC1,Out,Out1,Sync):-
  Clauses\=noclauses|
  resolve(Goal,Clauses,Subgoal,RC,RC1,not_susp,Out,Out1),
  schedule(Subgoal,T,NT,Sync).

reduce2(noclauses,Goal,T,NT,RC,RC1,Out,Out1,Sync):-
  true|
  Out=[undefined(Goal,NG)|Out1],
  schedule(NG,T,NT,Sync),
  RC=RC1.



resolve(Goal,[Clause|Cs],Subgoal,RC0,RC1,SF,Out,Out1):- 
  true|
  try_commit(Goal,Clause,Subgoal,Result),
  resolve2(Result,Goal,Cs,Subgoal,RC0,RC1,SF,Out,Out1).

resolve(Goal,[],Subgoal,RC0,RC1,suspend,Out,Out1):-
  true|
  Subgoal=Goal,
  RC1=RC0,
  Out=Out1.

resolve(Goal,[],Subgoal,RC0,RC1,not_susp,Out,Out1):-
  true|
  Out=[failure(Goal)].


resolve2(success,Goal,_,_,RC0,RC1,_,Out,Out1):-
  true|
  RC1:=RC0+1,
  Out=Out1.

resolve2(fail,Goal,Clauses,Subgoal,RC0,RC1,SF,Out,Out1):-
  true|
  resolve(Goal,Clauses,Subgoal,RC0,RC1,SF,Out,Out1).

resolve2(suspend,Goal,Clauses,Subgoal,RC0,RC1,SF,Out,Out1):-
  true|
  resolve(Goal,Clauses,Subgoal,RC0,RC1,suspend,Out,Out1).



reduce(Goal,T,NT,Sync):-
  true|
  clauses(Goal,Clauses),
  reduce2(Clauses,Goal,T,NT,Sync).


reduce2(Clauses,Goal,T,NT,Sync):-
  Clauses\=noclauses|
  resolve(Goal,Clauses,Subgoal,not_susp),
  schedule(Subgoal,T,NT,Sync).

reduce2(noclauses,Goal,T,NT,Sync):-
  true|
  Out=[undefined(Goal,NG)|Out1],
  schedule(NG,T,NT,Sync),
  RC=RC1.



resolve(Goal,[Clause|Cs],Subgoal,SF):- 
  true|
  try_commit(Goal,Clause,Subgoal,Result),
  resolve2(Result,Goal,Cs,Subgoal,SF).

resolve(Goal,[],Subgoal,suspend):-
  true|
  Subgoal=Goal.

resolve(Goal,[],Subgoal,not_susp):-
  true|
  Out=[failure(Goal)].


resolve2(success,Goal,_,_,_):-
  true|
  true.

resolve2(fail,Goal,Clauses,Subgoal,SF):-
  true|
  resolve(Goal,Clauses,Subgoal,SF).

resolve2(suspend,Goal,Clauses,Subgoal,SF):-
  true|
  resolve(Goal,Clauses,Subgoal,suspend).



clauses(Goal,Clauses):-
  true|
  functor(Goal,F,Arity,_),
  ps:clauses((F,Arity),Clauses).



try_commit(Goal,Clause,Subgoal,Result):-
  Clause=(Head:-Guard|Body)|
  head_unify(Goal,Head,Res1),
  solve_guard(Res1,Guard,Res2),
  commit(Res2,Clause,Subgoal,Result).



commit(success,Clause,Subgoal,Result):-
  true|
  Clause=(H:-G|Body),
  Subgoal=Body,
  Result=success.

commit(fail,_,_,Result):-
  true|
   Result=fail.   

commit(suspend,_,_,Result):-
  true|
    Result=suspend.

schedule(true,H,T,Sync):-
  true|
  T=H,
  Sync=go.

schedule((G,Gs),H,T,Sync):-
  true|
  H=[G|H1],
  schedule(Gs,H1,T,Sync).

otherwise.
schedule(G,H,T,Sync):-
  true|
  H=[G|T],
  Sync=go.



solve_guard(success,true,Res):-
  true|
  Res=success.

solve_guard(success,(Goal,Gs),Res):-
  true|
  solve_sys(Goal,Res0),
  solve_guard(Res0,Gs,Res).

solve_guard(fail,Goal,Res):-
  true|
  Res=fail.
solve_guard(suspend,Goal,Res):-
  true|
  Res=suspend.

otherwise.
solve_guard(success,Goal,Res):-
  true|
  solve_sys(Goal,Res).



solve_sys(true,Res):-
  true|
  Res=success.

solve_sys((X<Y),Res):-
  true|
  '<'(X,Y,Res).

solve_sys((X>Y),Res):-
  true|
  '>'(X,Y,Res).

solve_sys((X=<Y),Res):-
  true|
  '=<'(X,Y,Res).

solve_sys((X>=Y),Res):-
  true|
  '>='(X,Y,Res). %>=

solve_sys((X:=Y),Res):-
  true|
  ':='(X,Y,Res). %:=

solve_sys((X=\=Y),Res):-
  true|
  '=\='(X,Y,Res). %=\=

solve_sys((X=:=Y),Res):-
  true|
  '=:='(X,Y,Res).

solve_sys((X=Y),Res):-
  true|
  head_unify(X,Y,Res).

solve_sys((X\=Y),Res):-
  true|
  head_unify(X,Y,Res1),
  not_unify(Res1,Res).

solve_sys(not_unify(X,Y),Res):-
  true|
  head_unify(X,Y,Res1),
  not_unify(Res1,Res).

solve_sys(equal(X,Y),Res):-
  true|
  '=:='(X,Y,Res).

solve_sys(not_equal(X,Y),Res):-
  true|
  '=\='(X,Y,Res).

solve_sys(var(X),Res):-
  true|
  var(X,Res).


solve_sys(nonvar(X),Res):-
  true|
  nonvar(X,Res).

solve_sys(goal_or_command(X),Res):-
  true|
  goal_or_command(X,Res).

solve_sys(pragma(X,G,P,N),Res):-
  true|
  pragma(X,G,P,N,Res).

solve_sys(not_pragma(X),Res):-
  true|
  not_pragma(X,Res).

solve_sys(ad(Z,X,Y),Res):- 
  true|
  ':='(Z,'+',X,Y,Res).

solve_sys(sb(Z,X,Y),Res):-
  true|
  ':='(Z,'-',X,Y,Res).

solve_sys(md(Z,X,Y),Res):-
  true|
  ':='(Z,'mod',X,Y,Res).

solve_sys(rnd(R),Res):-
  true|
  Res=success.


':='(X,(A+B),Res):-
  true|
  ':='(X,'+',A,B,Res).

':='(X,(A-B),Res):-
  true|
  ':='(X,'-',A,B,Res).

':='(X,(A*B),Res):-
  true|
  ':='(X,'*',A,B,Res).

':='(X,(A/B),Res):-
  true|
  ':='(X,'/',A,B,Res).    
    

':='(X,'+',A,B,Res):-
  true|
  Y := A+B,
  unify(X,Y,Res).

':='(X,'-',A,B,Res):-
  true|
  Y := A-B,
  unify(X,Y,Res).

':='(X,'*',A,B,Res):-
  true|
  Y :=A*B,
  unify(X,Y,Res).

':='(X,'/',A,B,Res):-
  true|
  Y := A/B,
  unify(X,Y,Res).

':='(X,'mod',A,B,Res):-
  true|
  Y := A mod B,
  unify(X,Y,Res).

otherwise.
':='(X,_,_,_,Res):-
  true|
  Res=suspend.



'<'(X,Y,Res):-
  X<Y|
  Res=success.

'<'(X,Y,Res):-
  X>=Y|
  Res=fail.

otherwise.
'<'(X,Y,Res):-
  true|
  Res=suspend.



'>'(X,Y,Res):-
  X>Y|
  Res=success.
'>'(X,Y,Res):-
  X=<Y|
  Res=fail.

otherwise.
'>'(X,Y,Res):-
  true|
  Res=suspend.

'=<'(X,Y,Res):-
  X=<Y|
  Res=success.

'=<'(X,Y,Res):-
  X>Y|
  Res=fail.

otherwise.
'=<'(X,Y,Res):-
  true|
  Res=suspend.

'>='(X,Y,Res):-
  X>=Y|
  Res=success.

'>='(X,Y,Res):-
  X<Y|
  Res=fail.

otherwise.
'>='(X,Y,Res):- 
  true|
  Res=suspend.



'=\='(X,Y,Res):-
  true|
  unbound(X,XV),
  unbound(Y,YV),
  '=\='(XV,YV,X,Y,Res).

'=\='({_},{_},X,Y,Res):-
  X=Y|
  Res=fail.
'=\='({_,_,_},_,X,Y,Res):-
  true|
  Res=suspend.
'=\='(_,{_,_,_},X,Y,Res):-
  true|
  Res=suspend.
otherwise.
'=\='(_,_,X,Y,Res):-
  true|
  Res=success.



'=:='(X,Y,Res):-
  X=Y|
  Res=success.

'=:='(X,Y,Res):-
  X\=Y|
  Res=fail.

otherwise.
'=:='(X,Y,Res):-
  true|
  Res=suspend.



pragma(X,G,P,N,Res):-
  true|
  unbound(X,Bound),
  pragma(Bound,X,G,P,N,Res).
  
pragma(Bound,X,G,P,N,Res):-
  Bound={X}|
  pragma2(X,G,N,P,Res).

otherwise.
pragma(Bound,X,G,P,N,Res):-
  true|
  Res=suspend.


pragma2(X,G,P,N,Res):-
  X=bt(G1,P1)|
  pragma(X,G,N,P),
  Res=success.

otherwise.
pragma2(X,G,P,N,Res):-
  true|
  Res=fail.


pragma(bt(G1,P2),G,N,P):-
  G1=bt(G2,P3)|
  pragma(G1,G,N1,P1),
  N:=N1+1,
  P=(P1,P2).

otherwise.
pragma(bt(G1,P2),G,N,P):-
  true|
  G=G1,
  P=P2,
  N =1.



not_pragma(G,Res):-
  true|
  unbound(G,GV),
  not_pragma1(GV,Res).

not_pragma1({G},Res):-
  G=bt(G1,P)|
  Res=fail.

not_pragma1({_,_,_},Res):-
  true|
  Res=suspend.

otherwise.
not_pragma1(G,Res):-
  true|
  Res=success.



var(X,Res):-
  true|
  unbound(X,Y),
  var(X,Y,Res).

var(X,Y,Res):-
  Y={X}|
  Res=fail.

otherwise.
var(X,Y,Res):-
  true|
  Res=success.



nonvar(X,Res):-
  true|
  unbound(X,Y),
  nonvar(X,Y,Res).

nonvar(X,Y,Res):-
  Y={X}|
  Res=success.

otherwise.
nonvar(X,Y,Res):-
  true|
  Res=suspend.

goal_or_command(G,Res):-
  true|
  unbound(G,GV),
  goal_or_command1(GV,Res).

goal_or_command1({_,_,_},Res):-
  true|
  Res=suspend.

otherwise.
goal_or_command1({X},Res):-
  true|
  Res=success.


%unify(A,B,Result):-
%    true|
%    A=B,
%    Result=success.

unify(A,B,Result):-
  true|
  predicate_to_code(module#uni,unify_1,2,C2),
  shoen:execute(C2,{A,B},2000,4000,exception_tag#unification_failure,
                [start,add_resource(0,1000000)|X],R),
  checkR(R,X,Result).



head_unify(G,L,Result):-
  true|
  head_unification(G,L,success,Result).

head_unification(G,L,fail,Result):-
  true|
  Result=fail.

head_unification(G,L,success,Result):-
  true|
  binding(G,Gb),
  binding(L,Lb),
  try_h_unify(G,L,Gb,Lb,Result).

head_unification(G,L,suspend,Result):-
  true|
  Result=suspend.


 
binding(In,Out):-
  true|
  Out=(OutA,OutB),
  unbound(In,In2),
  binding2(In,In2,OutA,OutB).


binding2(In,In2,Atomic,Bound):-
  In2={_}|
  Bound=bound,
  binding3(In,Atomic).

binding2(In,In2,Atomic,Bound):-
  In2={_,_,_}|
  Atomic=no,
  Bound=unbound.


binding3(In,Atomic):-
  atom(In)|
  Atomic=atomic.

binding3(In,Atomic):-
  integer(In)|
  Atomic=atomic.

binding3(In,Atomic):-
  floating_point(In)|
  Atomic=atomic.

otherwise.
binding3(In,Atomic):-
  true|
  Atomic=structure.



try_h_unify(G,L,Gb,Lb,Res):-
  Gb=(_,unbound),
  Lb=(_,bound)|
  Res=suspend.

try_h_unify(G,L,Gb,Lb,Res):-
  Gb=(_,unbound),
  Lb=(_,unbound)|
  G=L,
  Res=success.

try_h_unify(G,L,Gb,Lb,Res):-
  Gb=(_,bound),
  Lb=(_,unbound)|
  L=G,
  Res=success.

try_h_unify(G,L,Gb,Lb,Res):-
  Gb=(atomic,bound),
  Lb=(atomic,bound),
  G=L|
  Res=success.

try_h_unify([HG|TG],[HL|TL],Gb,Lb,Res):-
  true|
  head_unification(HG,HL,success,Res1),
  head_unification(TG,TL,Res1,Res).

try_h_unify(G,L,Gb,Lb,Res):-
  Gb=(structure,bound),
  Lb=(structure,bound),
  vector(G,Size),
  vector(L,Size),
  vector_element(G,0,A),
  vector_element(L,0,A)|
  vector(G,_,Vg),
  vector(L,Size,Vl),
 unify_elements(Vg,Vl,1,Size,success,Res).

otherwise.
try_h_unify(G,L,Gb,Lb,Res):-
  true|
  Res=fail.



unify_elements(Vg,Vl,X,Size,Res,Res1):-
  X<Size,
  Res=success|
  vector_element(Vg,X,Eg,NVg),
  vector_element(Vl,X,El,NVl),
  head_unification(Eg,El,success,Res2),
  X2:=X+1,
  unify_elements(NVg,NVl,X2,Size,Res2,Res1).

otherwise.
unify_elements(Vg,Vl,X,Size,Res,Res1):-
  true|
  Res1=Res.



checkR([R|R2],X,Res):-
  R=exception(unification_failure,_,_,_)|
  Res=fail,
  X=[abort].

checkR([],X,Res):-
  true|
  X=[].

checkR([terminated|_],M,Res):-
  true|
  Res=success,
  M=[].

otherwise.
checkR([R|R2],X,Res):-
  true|
  checkR(R2,X,Res).



sum_q([exec(I,O,Q,T,RC,MRC)|QT],N):-
  true|
  sum_exec(Q,N1),
  sum_q(QT,N2),
  N = N1+N2.

sum_q([G|QT],N):-
  true|
  sum_q(QT,N1),
  N = N1+1.

otherwise.
sum_q(QT,N):-
  true|
  N=0.



sum_exec([G|QT],N):-
  true|
  sum_exec(QT,N1),
  N = N1+1.

otherwise.
sum_exec(QT,N):-
  true|
  N=0.



run_reflect(get_q(H,T),_,ET,ET,H,H,T,T,RC,RC1,MRC,MRC):-
  true|
  RC1 = RC+1.

run_reflect(put_q(Q,QT),_,ET,ET,_,Q,_,QT,RC,RC1,MRC,MRC):-
  true|
  RC1 = RC+1.

run_reflect(get_rc(RC,MRC),_,ET,ET,H,H,T,T,RC,RC1,MRC,MRC):-
  true|
  RC1 = RC+1.

run_reflect(put_rc(MRC),_,ET,ET,H,H,T,T,RC,RC1,_,MRC):-
  true|
  RC1 = RC+1.



reflect(get_q(_,_)):-
  true|
  true.

reflect(put_q(_,_)):-
  true|
  true.

reflect(get_rc(_,_)):-
  true|
  true.

reflect(put_rc(_)):-
  true|
  true.

reflect(get_ctbl(_)):-
  true|
  true.
 
reflect(put_ctbl(_)):-
  true|
  true.

reflect(get_atom(_)):-
  true|
  true.

reflect(put_atom(_)):-
  true|
  true.



throw(N,Q,T,Q,T):-
  N=<0|
  true.

throw(N,Q,T,Q,T):-
  Q=T|
  true.

throw(N,[exec(I,O,Q,T,RC,MRC)|Q1],T1,NQ,NT):-
  true|
  throw_exec(N,NN,Q,T,NQ0,NT0),
  NQ=[exec(I,O,NQ0,NT0,RC,MRC)|NT1],
  throw(NN,Q1,T1,NT1,NT).

throw(N,[G|Q1],T1,NQ,NT):-
  true|
  NQ=[G|NT1],
  throw(N,Q1,T1,NT1,NT).



throw_exec(N,N,Q,T,Q,T):-
  Q=T|
  true.
throw_exec(N,N,Q,T,Q,T):-
  N=<0|
  true.
throw_exec(N,NN,[rat(X)|Q],T,NQ,NT):-
  true|
  NQ=[bt(rat(X),forward)|NT1],
  N1 = N-1,
  throw_exec(N1,NN,Q,T,NT1,NT).

throw_exec(N,NN,[G|Q],T,NQ,NT):-
  true|
  NQ=[G|NT1],
  throw_exec(N,NN,Q,T,NT1,NT).



exec(EH,ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Sentry=(_,_,_,_),
  sentry(G,Sentry),
  exec(Sentry,EH,ET,In,Out,H,T,RC,MRC,Tail,NTail).


exec(Sentry,EH,ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  EH=ET|
  Tail=[exec(In,Out,H,T,RC,MRC)|NTail].

exec(Sentry,[G|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  Sentry=(_,true,_,_)|
  run_reflect(G,EH,ET,NET,H,NH,T,NT,RC,RC1,MRC,MRC1),
  Tail=[exec(EH,NET,In,Out,NH,NT,RC1,MRC1)|NTail].

exec(Sentry,[merge(S1,S2,S)|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  merge(S1,S2,S,ET,NET),
  Tail=[exec(EH,NET,In,Out,H,T,RC,MRC)|NTail].

exec(Sentry,[bt(G,P)|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  P=io|
  Out=[bt(G,io)|Out1],
  Tail=[exec(EH,ET,In,Out1,H,T,RC,MRC)|NTail].

exec(Sentry,[G|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  Sentry=(_,_,false,_)|
  reduce(G,ET,NET,RC,RC1,Out,Out1,Sync),
  Tail=[exec(EH,NET,In,Out1,H,T,RC1,MRC)|NTail].

exec(Sentry,[G|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  Sentry=(_,_,true,_)|
  solve_system(G,ET,NET,RC,RC1,Out,Out1),
  Tail=[exec(EH,NET,In,Out1,H,T,RC1,MRC)|NTail].

exec(Sentry,[true|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Tail=[exec(EH,ET,In,Out,H,T,RC,MRC)|NTail].

exec(Sentry,[false|EH],ET,In,Out,H,T,RC,MRC,Tail,NTail):-
  true|
  Out=[failure(false)],
  Tail=NTail.

exec(Sentry,_,_,In,Out,H,T,RC,MRC,Tail,NTail):-
  RC=MRC|
  Out=[over_count],
  Tail=NTail.



sentry(In,Out):-
  true|
  io(In,Out),
  reflect(In,Out),
  sys(In,Out),
  comp_goal(In,Out).

io(create_window(_Id,_S),(X,_,_,_)):-
  true|
  X=true.

io(create_subwindow(_Id,_S),(X,_,_,_)):-
  true|
  X=true.

io(create_subwindow(_Id,_XX,_YY,_S),(X,_,_,_)):-
  true|
  X=true.

io(link_channel(_S1,_C,_S2,_D1,_D2),(X,_,_,_)):-
  true|
  X=true.

io(see_channel(_S),(X,_,_,_)):-
  true|
  X=true.

otherwise.
io(Y,(X,_,_,_)):-
  true|
  X=false.



reflect(get_q(_,_),(_,X,_,_)):-
  true|
  X=true.

reflect(put_q(_,_),(_,X,_,_)):-
  true|
  X=true.

reflect(get_rc(_,_),(_,X,_,_)):-
  true|
  X=true.

reflect(put_rc(_),(_,X,_,_)):-
  true|
  X=true.

reflect(get_ctbl(_),(_,X_,_)):-
  true|
  X=true.

reflect(put_ctbl(_),(_,X,_,_)):-
  true|
  X=true.

reflect(get_atom(_),(_,X,_,_)):-
  true|
  X=true.

reflect(put_atom(_),(_,X,_,_)):-
  true|
  X=true.

otherwise.
reflect(Y,(_,X,_,_)):-
  true|
  X=false.

sys(true,(_,_,X,_)):-
  true|
  X=true.

sys((_=_),(_,_,X,_)):-
  true|
  X=true.

sys((_\=_),(_,_,X,_)):-
  true|
  X=true.

sys((_>_),(_,_,X,_)):-
  true|
  X=true.

sys((_>=_),(_,_,X,_)):-
  true|
  X=true.

sys((_<_),(_,_,X,_)):-
  true|
  X=true.

sys((_=<_),(_,_,X,_)):-
  true|
  X=true.

sys(ad(_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(var(_),(_,_,X,_)):-
  true|
  X=true.

sys(not_pragma(_),(_,_,X,_)):-
  true|
  X=true.

sys(pragma(_,_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(goal_or_command(_),(_,_,X,_)):-
  true|
  X=true.

sys(merge(_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(and(_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(exec(_,_,_,_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(exec(_EH,_ET,_I,_O,_H,_T,_RC,_MaxRC),(_,_,X,_)):-
  true|
  X=true.

sys(exec_susp(_I,_O,_H,_T,_RC,_MaxRC),(_,_,X,_)):-
  true|
  X=true.

sys(functor(_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(add(_,_,_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(reload(_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(rnd(_),(_,_,X,_)):-
  true|
  X=true.

sys(sum_q(_,_),(_,_,X,_)):-
  true|
  X=true.

sys(throw(_,_,_,_,_),(_,_,X,_)):-
  true|
  X=true.

sys(delay,(_,_,X,_)):-
  true|
  X=true.

otherwise.
sys(Y,(_,_,X,_)):-
  true|
  X=false.

comp_goal(proc_server(_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(susp_server(_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(subproc_server(_,_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(subsusp_server(_,_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(local_server(_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(lclsusp_server(_,_,_,_,_,_),(_,_,_,X)):-
  true|
  X=true.

comp_goal(Y,(_,_,_X)):-
  true|
  X=false.


