commute_bin_op(equal(A,B),Pred) :- compute_bin_op_equal(A,B,Pred).
commute_bin_op(greater_equal(A,B),less_equal(B,A)) :- can_be_used_for_lookups(B).
commute_bin_op(greater(A,B),Pred) :- compute_bin_op_less(B,A,Pred).
commute_bin_op(less_equal(A,B),Pred) :- compute_bin_op_less_equal(A,B,Pred).
commute_bin_op(less(A,B),Pred) :- compute_bin_op_less(A,B,Pred).
commute_bin_op(less_real(A,B),not_equal(A,B)). % TO DO: extend
commute_bin_op(subset_strict(A,B),Pred) :- gen_subset(A,B,Pred).
commute_bin_op(subset_strict(A,B),not_equal(A,B)).
commute_bin_op(subset(A,B),superset(B,A)) :- % new operator, for efficient lookups !
can_be_used_for_lookups(B).
commute_bin_op(not_subset(A,B),not_equal(A,B)). % also implies not_subset_strict
commute_bin_op(member(_,Set),not_equal(Set,empty_set)).
commute_bin_op(member(couple(A,B),C),NewHyp) :-
( NewHyp = member(A,domain(C)) % A|->B : C ==> A : dom(C)
; NewHyp = member(B,range(C)) ). % A|->B : C ==> B : ran(C)
commute_bin_op(member(X,interval(Low,Up)),NewHyp) :-
(NewHyp = less_equal(Low,Up) % x : Low..Up => Low <= Up
; NewHyp = less_equal(Low,X) % Low <= X if X: Low..UP
; can_be_used_for_lookups(X), NewHyp = greater_equal(X,Low)
; NewHyp = less_equal(X,Up) % X <= UP if X: Low..UP
; can_be_used_for_lookups(Up), NewHyp = greater_equal(Up,X)
).
commute_bin_op(member(X,Rel),NewHyp) :- is_total_relation(Rel,Domain),
% we cannot efficiently lookup this info from Domain
can_be_used_for_lookups(Domain),
NewHyp = equal(Domain,domain(X)).
commute_bin_op(member(X,Rel),NewHyp) :- is_surjective_relation(Rel,Range),
% we cannot efficiently lookup this info from Range
can_be_used_for_lookups(Range),
NewHyp = equal(Range,range(X)).
commute_bin_op(member(card(X),_),NewHyp) :- can_be_used_for_lookups(X),
NewHyp=finite(X).
commute_bin_op(disjunct(LHS,RHS),NewHyp) :- get_member_pred(LHS,X,A), get_member_pred(RHS,X,B),
NewHyp = member(X,union(A,B)).
commute_bin_op(disjunct(LHS,RHS),NewHyp) :- get_subset_pred(LHS,X,A), get_subset_pred(RHS,X,B),
NewHyp = subset(X,union(A,B)).
commute_bin_op(partition(A,List),equal(A,UNION)) :- gen_union(List,UNION).
commute_bin_op(forall(['$'(X)],LHSPred,RHSPred), Pred) :-
get_member_lhs(LHSPred,'$'(X),Set),
get_member_rhs(RHSPred,'$'(X),SET2),
useful_forall_superset(SET2),
% !x.(x:SET => x:dom(F)) => SET <: dom(F)
% !x.(x:SET => x:SET2) => SET <: SET2
not_occurs(Set,X),
not_occurs(SET2,X), %print(subset1(Set,SET2)),nl,
gen_subset(Set,SET2,Pred).
commute_bin_op(forall(['$'(X),'$'(Y)],LHSPred,RHSPred), Pred) :- % TO DO: generalise
get_member_lhs(LHSPred,couple('$'(X),'$'(Y)),Set), %TO DO: generalise -> domain/range
get_member_rhs(RHSPred,'$'(X),SET2),
useful_forall_superset(SET2),
% !x,y.(x|->y:SET => x:dom(F)) => dom(SET) <: dom(F)
% !x,y.(x|->y:SET => x:SET2) => dom(SET) <: SET2
not_occurs(Set,X),
not_occurs(Set,Y),
not_occurs(SET2,X), %print(subset2(Set,SET2)),nl,
gen_subset(domain(Set),SET2,Pred).
commute_bin_op(not_equal(A,B),equal(A,NB)) :- negate_boolean_like_value(B,NB).
commute_bin_op(not_equal(intersection(Set1,Set2),empty_set), Pred) :-
% Set /\ {a} /= {} => a : Set
(Set1=set_extension([A]),B=Set2 -> true ; Set2=set_extension([A]),B=Set1),
Pred = member(A,B).