%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% simple constraint solver for inequalities between variables
%% thom fruehwirth ECRC 950519, LMU 980207, 980311
%%
%% ported to hProlog by Tom Schrijvers 
%% translated into AR by N.F. Zhou, March 2006

main :-
	main(60).
%	main(15).

main(N):-
	cputime(X),
	length(L,N),
       genleq(L,Last,Eqs),
    writeln(gen_eq),
       geneq(Eqs),
	L=[First|_],
	leq(Last,First),
       writeln(L),
	cputime( Now),
	Time is Now-X,
	write(bench(leq ,N,Time,0,bp_ar)), write('.'),nl.

genleq([Last],Last,[]) :- ! .
genleq([X,Y|Xs],Last,[(Y1,Y)|Eqs]):-
	leq(X,Y1),
	genleq([Y|Xs],Last,Eqs).

geneq([]):-!.
geneq([(X,X)|Eqs]):-
    geneq(Eqs).

%%% reflexivity  @ leq(X,X) <=> true.   % Occ 1
%%% antisymmetry @ leq(X,Y), leq(Y,X) <=> X = Y. % Occ 2 and 3, combined 23
%%% idempotence  @ leq(X,Y) \ leq(X,Y) <=> true. % Occ 4 and 5, combined 45
%%% transitivity @ leq(X,Y), leq(Y,Z) ==> leq(X,Z). % Occ 5 6
leq(X,Y):-
    new_constr_num(Cno),
    Constr=leq(Cno,Flag,X,Y),  
    %
    leq_2_1(Flag,X,Y),
    %
    % A1XCh?: All constraints that have X as the first argument 
    % A2XCh?: All constraints that have X as the second argument 
    % A1YCh?: All constraints that have Y as the first argument 
    % A2YCh?: All constraints that have Y as the second argument 
    Channels=chs(A1XCh2,A1XCh3,A1XCh4,A2XCh2,A2XCh3,A2XCh4,A1YCh2,A1YCh3,A1YCh4,A2YCh2,A2YCh3,A2YCh4),
    get_channels(leq_3_arg1,X,chs(A1XCh2,A1XCh3,A1XCh4)),
    get_channels(leq_3_arg2,X,chs(A2XCh2,A2XCh3,A2XCh4)),
    get_channels(leq_3_arg1,Y,chs(A1YCh2,A1YCh3,A1YCh4)),
    get_channels(leq_3_arg2,Y,chs(A2YCh2,A2YCh3,A2YCh4)),

    %
    leq_2_23(Cno,A1XCh2,A2YCh2,Flag,X,Y),    
    %
    leq_2_45(Cno,A1XCh3,A2YCh3,Flag,X,Y),
     %
    new_hashtable(History),
    leq_2_56(Cno,A1XCh4,A2YCh4,Flag,History,X,Y),
    %
    post_leq_3(Flag,Channels,Constr,X,Y).

%%    Called when either variable in leq(X,Y) is instantiated
post_leq_3(Flag,Channels,Constr,X,Y),var(Flag),
    {generated,ins(Flag),ins(X),ins(Y)} 
=>
    Channels=chs(A1XCh2,A1XCh3,A1XCh4,A2XCh2,A2XCh3,A2XCh4,A1YCh2,A1YCh3,A1YCh4,A2YCh2,A2YCh3,A2YCh4),
    get_channels(leq_3_arg1,X,chs(A1XCh2,A1XCh3,A1XCh4)),
    get_channels(leq_3_arg2,X,chs(A2XCh2,A2XCh3,A2XCh4)),
    get_channels(leq_3_arg1,Y,chs(A1YCh2,A1YCh3,A1YCh4)),
    get_channels(leq_3_arg2,Y,chs(A2YCh2,A2YCh3,A2YCh4)),
    %
    (var(Flag)->post_event(A1YCh2/\A2XCh2,Constr);true), % to agents leq(Y,X)
    %
    (var(Flag)->post_event(A1XCh3/\A2YCh3,Constr);true), % to agents leq(X,Y) 
     %
    (var(Flag)->post_event_df(A1YCh4\/A2XCh4,Flag,Constr);true). % to agents leq(Y,_) or leq(_,X)
post_leq_3(Flag,Channels,Constr,X,Y) => true.

leq_2_1(Flag,X,Y),var(Flag),
    {generated,ins(Flag),ins(X),ins(Y)} 
=> 
    (X==Y->Flag=1;true).
leq_2_1(Flag,X,Y) => true.

%%% antisymmetry @ leq(X,Y), leq(Y,X) <=> X = Y.
leq_2_23(Cno,C1,C2,Flag,X,Y),var(Flag),{event(C1,Q),event(C2,Q),ins(Flag)} =>
     Q=leq(CnoQ,FlagQ,U,V),
     (CnoQ\==Cno,var(FlagQ)->  
         (X==V,Y==U -> Flag=1,FlagQ=1,X=Y;true)
      ;
          true
      ).
leq_2_23(Cno,C1,C2,Flag,X,Y) => true.

%%% idempotence  @ leq(X,Y) \ leq(X,Y) <=> true.
leq_2_45(Cno,C1,C2,Flag,X,Y),var(Flag),{event(C1,Q),event(C2,Q),ins(Flag)} =>
     Q=leq(CnoQ,FlagQ,U,V),
     (CnoQ\==Cno,var(Flag),var(FlagQ)->
          (X==U,Y==V -> FlagQ=1;true)
      ;
          true
      ).
leq_2_45(Cno,C1,C2,Flag,X,Y) => true.

%%% transitivity @ leq(X,Y), leq(Y,Z) ==> leq(X,Z).
% no instance can be fired more than once
leq_2_56(Cno,C1,C2,Flag,History,X,Y),var(Flag),{event(C1,Q),event(C2,Q),ins(Flag)} =>
     Q=leq(CnoQ,FlagQ,U,V),
     (CnoQ\==Cno,var(FlagQ)->
        (hashtable_get(History,CnoQ,_)-> 
            true
         ;Y==U->
%              writeln((leq(Cno,X,Y),leq(CnoQ,U,V)=>leq(X,V))),
            hashtable_put(History,CnoQ,_),
            leq(X,V)
          ;X==V->
%            writeln((leq(CnoQ,U,V),leq(Cno,X,Y)=>leq(U,Y))),
            hashtable_put(History,CnoQ,_),
            leq(U,Y)
	   ; 
            true
          )
      ;
          true
      ).
leq_2_56(Cno,C1,C2,Flag,History,X,Y) => true.


:-include('chr_lib.pl').