:- publicall.
/*
    << AZ-Prolog CLP predicate  V.1 2013.08.15 >>
V.2 2015.03.30  add turukame pattern

制約論理関連述語

< HighLevel Builtin Predicate >
	det:freeze/2 
	det:frozen/2 

< LowLevel Builtin Predicate >
	det: system_get_min_max_int/2      % Get Integer Min & Max
	det: get_clp_area/2                % Using indomain/1 etc
	det: put_clp_area/2                % Allmost in/2
	det: rm_clp_area/2                 % Allmost notin/2 
	det: clp_intersection/3 
	det: clp_is_member/2 

< Prolog Source(clp.pl) Compiled Predicate >
	nondet: indomain/1
	nondet: labeling/1
	det: in/2
	det: notin/2
	det: alldifferent/1
	det: outof/3                       % Demon of alldifferent/1
	det:  #=
	det:  #\=
	det:  #<
	det:  #>
	det:  #=<
	det:  #>=

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
<1> 
【述語】
	freeze/2

【書式】
	freeze(?T,+Goal)               

【引数】
	?T    未代入変数、任意の項
	+Goal ゴール(列） 

【説明】
	1) Tが未代入変数のとき、将来Tに値が束縛されたときに実行するGoalを設定します。
	2) Tが値を持っているときは直ちGoalを実行します。
	3) Goalを順次追加することができます。ここでは追加されたGoalを含む全体をゴール列と呼びます。
	4) freeze/2が呼び出された節より前にバックトラックしたときは、設定が解除されます。
	5) ゴール列の最後は常に述語"!"がつきます。すなわち実行されるゴール列が終了するときは決定性です。
	   ただし、ゴール列の間では非決定です。
	6) Goalが変数の場合も成功しますが、呼び出されるときには値が決まっていないとエラーになります。

【関連述語】
	frozen/2,in/2,notin/2

【実行例】

	(1)
	| ?- freeze(X,(write(first),nl)),write(second),nl,X=1.
	second             <== write(second)が評価されるときには、変数Xは未代入です。	
	first              <== 変数Xが値を持ったときに設定されたゴールが実行されます
	X = 1
	yes	

	(2)
	| ?- X=1,freeze(X,(write(first),nl)),write(second),nl.
	first              <== Xがすでに値をもっているので直ちに設定ゴールが実行されます
	second	
	X = 1
	yes
    
	(3)
	| ?- freeze(X,(write(first),nl)),freeze(X,(write(second),nl)),X=1.
	first              <== 変数Xが値を持ったときに設定されたゴール列が次々に実行されます
	second             <=+ 
	X = 1
	yes

	(4)
	| ?- freeze(X,(write(first),nl)),( freeze(X,(write(second),nl)),fail ; true ),X=1.
	first              <== 二番目のfreeze/2を含むゴール列がFailしたので、取り消されています
	X = 1
	yes

	(5)
	| ?-freeze(X,(member(A,[a,b,c]))),freeze(X,(write(A),nl)),X=1,fail.
	a
	no
	| ?-freeze(X,(member(A,[a,b,c]))),freeze(X,(write(A),nl)),freeze(X,fail),X=1.
	a
	b
	c
	no

	(6)
	| ?-freeze(X,L),X=1.           
	Illegal Goal     ---- Backtrace
	(freeze(1,L_13),=(1,1)) ?-

	| ?-freeze(X,L),L=write(a),X=1.
	a
	X  = 1,
	L  = write(a)
	yes


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<2> 
【述語】
	frozen/2

【書式】
	frozen(?T,-Goal)

【引数】
	?T    未代入変数、任意の項
	-Goal ゴール(列） 

【説明】
	1) T が未代入変数でfreeze されたゴールがある場合、これをGoal と単一化します
	2) その他の場合、Goal とtrueを単一化します。

【関連述語】
	freeze/2,in/2,notin/2

【実行例】
	(1)
	| ?-freeze(X,member(X,[a,b,c])),frozen(X,G).
	X       = X,
	G       = member(_24,[a,b,c]),!

	| ?-freeze(X,member(f(X),[f(a),d(b),c])),freeze(X,write(X)),frozen(X,G).
	X       = X,
	G       = member(f(_24),[a,b,c]),write(_24),!

	(2)
	| ?-freeze(X,write(a)),X=1,frozen(X,L).
	a
	X       = 1,
	L       = true

	| ?-frozen(X,L).
	X	= X
	L	= true
	
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<3>
【述語】
	in  /xfx	
【書式】
	?T1 in +T2
	
【引数】
	T1: [1]未代入変数 または項
	    [2] T1:[1]を要素とするリスト 	
	T2: [1] T1が束縛されるべき項（T2:[2]の表現を含む）の列挙リスト、
	    [2] またはT1が束縛されるべき整数の範囲表現　N1..N2 (N1,N2は整数でN1=<N2) 　

【説明】
	1) T1が値を持つとき、 T1はT2の要素のいずれかであるとき成功する
	2) T1が未代入変数のとき、T1はT2の要素のいずれかであると制約される
	   将来T1が値を持つとき、この制約の範囲であれば成功し、範囲外であれば失敗する
	   T1がリストの場合、個々の要素について 1),2) が摘要される。
	3) 複数の制約を受けるとき、それらの制約の積となる。
	4) 制約によって値が一意にきまるときは、T1の値は決定し成功する
	5) 矛盾する制約が与えられたときは失敗する

【関連述語】
	freeze/2,frozen/2,notin/2

【実行例】
	(1)
	| ?- 3 in 0..10.
	yes

	| ?- b in [a,b,c,1..10,d(X)].
	yes

	(2)
	| ?- X in 0..9.
	X   = X
	yes

	| ?- X in 0..9,X=3.
	X   = 3 
	yes

	| ?- X in 0..9,X=20.
	no

	| ?- X in [a,b,c,d], member(X,[z,c,d,e,f]).
	X   = c
	yes

	| ?-[X,Y] in 0..9,X=3.
	X       = 3,
	Y       = Y
	yes

	(3)
	| ?- X in 0..9,X in 8..10.      <==  X in [8,9] となる
	X   = X
	yes	

	(4)
	| ?- X in 0..9,X in 9..10.      <== 値が二つの制約の積により一意化する
	X   = 9
	yes	

	(5)
	| ?- X in 0..9,X in 15..16.     <== Xのとるべき値はないので失敗する
	no

	(6) 次の二つは異なることに注意してください。
	| ?- X in 0..4,X in 5..7.       <== X は0,1,2,3,4 かつ X は5,6,7 
	no
	| ?- X in [0..4,5..7]           <== X は0,1,2,3,4,5,6,7のいずれか
	yes

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<4>
【述語】
	notin  /xfx	
【書式】
	?T1 notin +T2
	
【引数】
	T1: [1] 未代入変数 または、項
	    [2] T1:[1]を要素とするリスト
	T2: [1] T1が束縛されざるべき項（T2:[2]の表現を含む）の列挙リスト、
	    [2] またはT1が束縛されざるべき整数の範囲表現　N1..N2 (N1,N2は整数でN1=<N2) 　

【説明】
	1) T1が値を持つとき、 T1はT2の要素のいずれかでないとき成功する
	2) T1が未代入変数のとき、T1はT2の要素のいずれかでないと制約される
	   将来T1が値を持つとき、この制約の範囲であれば失敗し、範囲外であれば成功する
	   T1がリストの場合、個々の要素について 1),2) が摘要される。
	3) 複数の制約を受けるとき、それらの制約の積となる。
	4) 制約によって値が一意にきまるときは、T1の値は決定し成功する
	5) 矛盾する制約が与えられたときは失敗する

【関連述語】
	freeze/2,frozen/2,in/2

【実行例】
	(1)
	| ?- 3 notin 0..10.
	no	

	| ?- 11 notin 0..10.
	yes	

	| ?- b in [a,b,c,1..10,d(X)].
	no	

	(2)
	| ?- X notin 0..9.
	X   = X
	yes

	| ?- X notin 0..9,X=3.
	no

	| ?- X notin 0..9,X=20.
	X   = 20
	yes	

	| ?- X notin [a,b,c,d], member(X,[a,b,c,d,e,f]).
	X   = e;
	X   = f;
	no	

	(3)
	| ?- X in 0..9,X notin 8..10.      <==  X in 0..7 となる
	X   = X
	yes	

	(4) 
	| ?- X in 0..9,X notin 0..8.       <== Xの値が二つの制約の積により一意化する
	X   = 9 
	yes	

	(5)
	| ?- X in 0..9,X notin 0..9.       <== Xのとるべき値はないので失敗する
	no

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<5>
【述語】
	alldifferent/1
【書式】
	alldifferent(+L)
【引数】
	L : 項を要素とするリスト
【説明】
	1)リストの要素がすべて異なる値を持つ場合に成功する
	2)リストに変数が含まれる、またはすべて変数の場合、リストの要素が
	  すべて異なる値を持たねばならない制約を与える

【関連述語】
	freeze/2,frozen/2,in/2,notin/2

【実行例】
	| ?- alldifferent([1,2,3,4]).
	yes
	| ?- alldifferent([1,2,3,4,1]).
	no	
	| ?- alldifferent([1,2,3,A,1]).
	yes	
	| ?- alldifferent([1,2,3,A,A]).
	no	
	| ?- V=[A,B,C],V in 0..9,alldifferent(V).
	yes	

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<6>
【述語】
	indomain/1
【書式】
	indomain(?T)
【引数】
	T: 領域制約された未代入変数,または値を持つ項
【説明】
	1) Tが値を持つ項の場合は直ちに成功する
	2) 領域制約された未代入変数の場合は、Tに可能な値を順に束縛する非決定述語
	3)  1,2	以外はエラー(Illegal Argument supplied)

【関連述語】
	freeze/2,frozen/2,in/2,notin/2,labeling/1

【実行例】
	| ?- indomain(1).
	yes

	| ?- X in 1..3,indomain(X).
	X = 1;
	X = 2;
	X = 3;
	no

	| ?- indomain(X).
	Illegal Argument Supplied..

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%	
<7>
【述語】
	labeling/1
【書式】
	labeling(?L)
【引数】
	L: 制約変数、項のリスト 
【説明】                  
	Lに含まれる全要素を順に実体化する。探索。
	定義は次のとおり 

	labeling(V):- var(V),!,labeling([V]).
	labeling([V|L]):-!,indomain(V),labeling(L).
	labeling([]).

【関連述語】
	freeze/2,frozen/2,in/2,notin/2,indomain/1

【実行例】
	| ?- V=[A,B,C],V in 0..4,alldifferent(V),labeling(V).
	V  = [0,1,2],
	A  = 0,
	B  = 1,
	C  = 2;
	V  = [0,1,3],
	A  = 0,
	B  = 1,
	C  = 3

##################################
8) 数式1 #= 数式2                  数式1と数式2は 等式であるという制約
9) 数式1 #\= 数式2                 数式1と数式2は 異なる値をとるという制約
10) 不等式

   制約済変数(例 X::0..9)
   ?- X in 0..9,X #=< 8.    X:0..8
   ?- X in 0..9,X #<  8.    X:0..7
   ?- X in 0..9,X #>= 8.    X:[8,9]
   ?- X in 0..9,X #>  8.    X:[9]  --->  X=9    Xの値が自動的にもとまる
   ?- X in 0..9,X #\= 7.    X:[0..6,8,9]

   未制約済変数
   ?- X #=< 8.    X:-整数下限..8
   ?- X #<  8.    X:-整数下限..7
   ?- X #>= 8.    X:[8..整数上限]
   ?- X #>  8.    X:[9..整数上限]
   ?- X #\= 7.    X:freeze(X,X \== 7)


 < CLP変数の構造 >
			CLP_CELL
   [clp_tag:Pointer]--->[undef_tag: Value Area]
                        [List:Poniter] -->car:[ConstAreaList] cdr:[undef]
                        ,(DelayGoal,Undef)

   When Undef:clp_cell Unified by Any value(except undef)
   1) Check if Value is within ConstAreaList else FAIL
   2) invoke DelayGoal 
 
   When Undef:clp_cell Unified by Other Undef:clp_cell
   1) Marge ConstAreaLists 
   2) Marge DelayGoals

*/

:- s_mode(_,on).

%% Builtin  Predicate (writen by C-lang) %%
:- extern det:freeze/2.
:- extern det:frozen/2.

  %%% Low Level Builtin Predicate %%%
:- extern det:get_clp_area/2.               % Reference CLP Area
:- extern det:put_clp_area/2.               % Renew CLP Area
:- extern det:system_get_min_max_int/2.     % Get Integer Min & Max

%% Builtin (Compiled Prolog) Hand optimized Predicate Source is Under This File
:- extern det:rm_clp_area/2.
%:- extern det:outof/3.
:- extern det:clp_intersection/3.
:- extern det:clp_is_member/2.

%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% clp_version/1 %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%
:- public clp_version/1.

clp_version('clp-version: 0.3').

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  ?- Vars := [A,B,C].  %%
%%  制約領域の設定述語   %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public  ':=' /2.
':='(X,Y) :- var(X),!,X=Y.
':='(X,Y) :- error(100).

%%%%%%%%%%%%%%%%%%%%%%
%%%%% labeling/1 %%%%%
%%%%%%%%%%%%%%%%%%%%%%
:- public labeling/1.
labeling(V):- var(V),!,labeling([V]).
%% labeling([V|L]):- list(V),!,labeling(V),labeling(L).   %added V2
labeling([V|L]):-!,indomain(V),labeling(L).
labeling([]).

%%%%%%%%%%%%%%%%%%%%%%
%%%%% indomain/1 %%%%%
%%%%%%%%%%%%%%%%%%%%%%
:- public indomain/1.
indomain(V):- get_clp_area(V,Area),!,clp_member(V,Area).
indomain(V):- var(V),!,error(9).
indomain(V).

  %%%
clp_member(X,[N..Y|L]):- clp_int_gen(X,N,Y).
clp_member(X,[N..Y|L]):- !,clp_member(X,L).
clp_member(X,[X|_]).
clp_member(Y,[_|L]):- clp_member(Y,L).

clp_int_gen(V,N,Y):- N =< Y,V=N.
%clp_int_gen(V,N,Y):- N =< Y,NN is N+1,clp_int_gen(V,NN,Y).
clp_int_gen(V,N,Y):- NN is N+1,NN =< Y,clp_int_gen(V,NN,Y).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ?- alldifferent(Vars).  %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public alldifferent/1.

alldifferent(X):- 
	clp_pickup_adf(X,[],Const,[],Allvars),
	clp_pickup_adf2(Allvars,Const),     % rm_clp_area
	clp_alldifferent(Allvars,[]).

clp_alldifferent([],_):-!.
clp_alldifferent([A|X],S):-freeze(A,outof(A,S,X)),clp_alldifferent(X,[A|S]).

  %%% OrgList divide into ConstList,CLPVarList,OtherVarList
clp_pickup_adf([],Const,Const,  Var,Var):-!.
clp_pickup_adf([A|L],CT,CTO,    Var,VarO):-
	nonvar(A),!,not_mymember(A,CT),
	clp_pickup_adf(L,[A|CT], CTO,Var,VarO).
clp_pickup_adf([A|L],CT,CTO,Var,VarO):-
	not_mymember(A,Var),
	clp_pickup_adf(L, CT,CTO, [A|Var],VarO).

not_mymember(A,[]):-!.
not_mymember(A,[B|L]):- A\==B,not_mymember(A,L).

  %%% rm Const From CLP/Var
clp_pickup_adf2(_,[]):-!.
clp_pickup_adf2([],_):-!.
clp_pickup_adf2([A|L],Const):- A notin Const,clp_pickup_adf2(L,Const).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public outof/3 .

outof(A,Before,After):- clp_notmember2(A,Before),clp_notmember2(A,After).

clp_notmember2(A,[]):- !.
clp_notmember2(A,[B|L]):- get_clp_area(B,_),!,rm_clp_area(B,A),clp_notmember2(A,L).
clp_notmember2(A,[B|L]):- var(B),!,freeze(B,B\==A),clp_notmember2(A,L).
clp_notmember2(A,[B|L]):- A \==B,clp_notmember2(A,L).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public #= /2.

#=(L,R) :-   clp_primitive(L),clp_primitive(R),!,L=R.
#=(A-B,0):-  A #= B,!.
#=(-A+B,0):- A #= B,!.

% #=(L,R*N) :- clp_mlt(L,R,N),!.
#=(L,R+N) :- clp_add(L,R,N),!,M is -1*N,clp_add(R,L,M).
#=(L,R-N) :- clp_add(R,L,N),!,M is -1*N,clp_add(L,R,M).
% #=(X,Y):- #=(Y,X),!.
   %%% Hukumenzan %%%
/*  #=(X,Y):-   2014.5.20 delete */
#=(X0,Y0):- 
	(X0 @>= Y0 ->X=X0,Y=Y0;X=Y0,Y=X0),   /* 2014.5.20 insert */
	clp_form2(X-(Y),A), 
	clp_hsort(A,[],Z),
	clp_hukumen(Z,0,[],L,1),
	!,clp_every_call(L).
   %%% ELSE %%%
#=(L,R) :- clp_form(L-(R),Num,Ks,Vars),clp_set_top(Vars,Num,Ks).

clp_hsort([],L1,L1):-!.
clp_hsort([X|L],L1,L2):-
	h_partition(X,L,L3,L4),clp_hsort(L4,L1,L5),clp_hsort(L3,[X|L5],L2).

h_partition(X,[],[],[]):-!.
h_partition(X,[A|L],L1,[A|L2]):-X@<A,!,h_partition(X,L,L1,L2).
h_partition(X,[A|L],[A|L1],L2):-h_partition(X,L,L1,L2).

%%%%%%%%%%%%%%%%%%%
/*
#=(X,Y) :- clp_value_countup(X-Y,0,C,PVar,MVar),
clp_value_countup(C,C,UC,C):-var(C),!,clp_value_countup(B,
clp_value_countup(A+B,C,UC,Var):-nonvar(C),clp_value_countup(B,
*/

%%%%%%%%%%%%%%%%%%%
clp_every_call([]):-!.
clp_every_call([A|L]):- #=(A,0),!,clp_every_call(L).

%%%%%%%%%%%%%%%%%%%
% :- dynamic clp_hukumen/7.
clp_hukumen([],Q,L,[Q|L],_):-!.
clp_hukumen([NY|R],Q,L,LO,N):- 
        clp_add_que(NY,N,Q,NewQ),!,clp_hukumen(R,NewQ,L,LO,N).
clp_hukumen(NYR,Q,L,LO,M):- 
        clp_hukumen_check(NYR,M,N),
	put_clp_area(C2,[0,1]),clp_hukumen(NYR,C2,[Q-10*C2|L],LO,N).

clp_add_que(N*Y,   N,Q,Q+Y):- var(Y),!.
clp_add_que(N*(-Y),N,Q,Q-Y).

clp_hukumen_check([N*Y|_],M,N):- N is M*10.
%%%%%%%%%%%%%%%%%%%
% :- dynamic clp_form2/2.
clp_form2(X,Y):- clp_form2(X,1,Y-[]).

% :- dynamic clp_form2/3.
clp_form2(X,N,[1*X0|L]-L):- var(X),!,clp_var_check2(N,X,X0).
clp_form2(X*Y,N,[XXYY|L]-L):-!,clp_var_check(X,Y,XXYY,N).
clp_form2(X+Y,N,Ans-T):-!, clp_form2(X,N,Ans-T2),clp_form2(Y,N,T2-T).
clp_form2(X-Y,N,Ans-T):-clp_form2(X,N,Ans-T2),NN is -1*N,clp_form2(Y,NN,T2-T).

% :- dynamic clp_var_check/5.
clp_var_check(X,Y,X*Y0,N):-  integer(X),var(Y),!,clp_var_check2(N,Y,Y0).
clp_var_check(Y,X,X*Y0,N):-  integer(X),var(Y),!,clp_var_check2(N,Y,Y0).

clp_var_check2(1,Y,Y):-!.
clp_var_check2(_,Y,-Y).

/*
clp_mlt(L,R,N):- clp_primitive(L),integer(R),integer(N),!,L is R*N.
clp_mlt(L,R,N):- clp_primitive(R),integer(L),integer(N),!,R is L/N.
clp_mlt(L,R,N):-
	var(L),var(R),
	( get_clp_area(R,A) -> clp_mlt_area(A,N,AD)
		; system_get_min_max_int(Min,Max),
		  put_clp_area(R,[Min..Max]),
		  Min2 is Min*N,AD=[Min2..Max] ),
	freeze(R,L is R*N), freeze(L,R is L/N),
	put_clp_area(L,AD).
*/

clp_add(L,R,N):- clp_primitive(L),integer(R),integer(N),!,L is R+N.
clp_add(L,R,N):- clp_primitive(R),integer(L),integer(N),!,R is L-N.
clp_add(L,R,N):-
	var(L),var(R),
	( get_clp_area(R,A) -> clp_add_area(A,N,AD)
		; system_get_min_max_int(Min,Max),
		  put_clp_area(R,[Min..Max]),
		  Min2 is Min+N,AD=[Min2..Max] ),
	freeze(L,R is L-N), put_clp_area(L,AD).

clp_primitive(X):- var(X),!.
clp_primitive(X):- atomic(X),!.

clp_mlt_area([],_,[]):-!.
clp_mlt_area([X..Y|L],A,[M..N|R]):- M is X*A,N is Y*A,!,clp_mlt_area(L,A,R).
clp_mlt_area([N|L],A,[M|R]):- M is N*A,!,clp_mlt_area(L,A,R).

clp_add_area([],_,[]):-!.
clp_add_area([X..Y|L],A,[M..N|R]):- !,M is X+A,N is Y+A,clp_add_area(L,A,R).
clp_add_area([N|L],A,[M|R]):- M is N+A,!,clp_add_area(L,A,R).

%%%%%%%%%%%%%

clp_set_top([],_,_):- !.
clp_set_top([Var],Num,[Ks]):-
	!,Var0 is Num/Ks,
	(0.0 is float_fractional_part(Var0) -> Var is integer(Var0) ; Var=Var0). 
clp_set_top(Vars,Num,Ks):- 
	clp_all_1(Ks),!,
	clp_area_reset3(Vars,Num),
	clp_set(Vars,'$clp_area_propagation3'(Num,Vars)),
	clp_check_for2v(Vars).

clp_set_top(Vars,Num,Ks):-
	clp_area_reset(Vars,Num,Ks), 
	clp_set(Vars,'$clp_area_propagation'(Num,Ks,Vars)),
 	clp_check_for2v(Vars).

% 2015.3.29
clp_check_for2v([A,B]):-
	frozen(A,AF),
	clp_check_for2v2(AF,A,B,1),
	frozen(B,BF),
	clp_check_for2v2(BF,B,A,0),!.
%	clp_check_for2v([A,B]).
clp_check_for2v(_).

get_frozen_area(('$clp_area_propagation'(Num,Kei,[_,_]),Else),Num,Kei,Else):-!.
get_frozen_area(('$clp_area_propagation3'(Num,[_,_]),Else),Num,[1,1],Else):-!.
get_frozen_area((_,Else),Num,Arg,Other):- get_frozen_area(Else,Num,Arg,Other).

clp_check_for2v2(AF,A,B,Flag):- 
	get_frozen_area(AF,Num,[K10,K20],Else),	
	(Flag == 1 -> K1=K10,K2=K20;K1=K20,K2=K10),
	get_clp_area(A,AL),
	get_clp_area(B,BL),
	clp_check_for2v3(Num,K1,AL,OK-OK,K2,BL,BOK),
	A in OK,
	B in BOK,!,
	clp_check_for2v2(Else,A,B,Flag).
clp_check_for2v2(AF,A,B,_). 

clp_check_for2v3(_,_,[],OK-[],_,_,[]):-!.
clp_check_for2v3(Num,K1,[A..B|L],OK-R,K2,BL,BOK):-!,
	!,clp_gen_num(A,B,Gen,L),
	clp_check_for2v3(Num,K1,Gen,OK-R,K2,BL,BOK).
clp_check_for2v3(Num,K1,[C|L],OK-[C|R],K2,BL,[X|BOK]):-
	clp_member(X,BL),Num is K1*C+K2*X,!,
	clp_check_for2v3(Num,K1,L,OK-R,K2,BL,BOK).
clp_check_for2v3(Num,K1,[_|L],OK-R,K2,BL,BOK):-
	clp_check_for2v3(Num,K1,L,OK-R,K2,BL,BOK).
	
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* If Total is odd,and Only1Var is odd */
/* If Total is even,and AllVar must be even or even odds */
clp_area_reset(Vars,Num,Ks):-
	Odd_even is Num mod 2,
	clp_only1_odd(Vars,Ks,0,V,Vks,EV,EVKs), /*OnlyOne coefficient must odd*/
	get_clp_area(V,L),!,
	rm_even_odd(L,R,Odd_even),	/* Odd coefficient Var must odd */
	put_clp_area(V,R),
	clp_area_reset2(Num,R,Vks,EV,EVKs).

clp_area_reset(Vars,Num,Ks).

%%%% Total,BaseVar,
clp_area_reset2(Num,R,Vks,[EV],[EVKs]):- 
	mk_other_area(Num,R,Vks,  EVKs,[],Area),
	!,EV in Area.
clp_area_reset2(Num,R,Vks,EV,EVKs). 

%% 
clp_area_reset3([A,B],Num):-
	get_clp_area(A,KA),
	get_clp_area(B,KB),!,
	clp_area_reset2(Num,KA,1,[B],[1]),
	( get_clp_area(B,KBB),KB \== KBB -> clp_area_reset3([B,A],Num); true).
clp_area_reset3(_,_).

mk_other_area(Num,[],VKs,   EVKs,Area,Area):-!.
mk_other_area(Num,[A..B|L],VKs,EVKs,Stack,Area):-
	!,clp_gen_num(A,B,Gen,L),mk_other_area(Num,Gen,VKs,EVKs,Stack,Area).
mk_other_area(Num,[A|L],VKs,EVKs,Stack,Area):-
	integer(A),
	OK0 is (Num - A*VKs)/EVKs,
	0.0 is float_fractional_part(OK0),
	OK is integer(OK0),!,
	mk_other_area(Num,L,VKs,EVKs,[OK|Stack],Area).
mk_other_area(Num,[_|L],VKs,EVKs,Stack,Area):-
	mk_other_area(Num,L,VKs,EVKs,Stack,Area).

clp_odd_num(Num):- 1 is Num mod 2.
clp_even_num(Num):- 0 is Num mod 2.

%% VarList,KeisuList,Flag,OddVar,OddVarsKeisu,Evenvars,EvenvarsKeisu
clp_only1_odd([],[],1,_,_,[],[]):- !.
clp_only1_odd([V|Vars],[K|Ks],F,V,K,E,EKs):- 
	clp_odd_num(K),!,F==0,clp_only1_odd(Vars,Ks,1,_,_,E,EKs).
clp_only1_odd([V|Vars],[K|Ks],N,V,VK,[V|E],[K|EKs]):- 
	clp_only1_odd(Vars,Ks,N,V,VK,E,EKs). 

rm_even_odd([],[],_):- !.
rm_even_odd([A..B|L],R,Flag):- !,clp_gen_num(A,B,Gen,L),rm_even_odd(Gen,R,Flag).
rm_even_odd([A|L],R,1):- clp_even_num(A),!,rm_even_odd(L,R,1).
rm_even_odd([A|L],R,0):- clp_odd_num(A),!,rm_even_odd(L,R,0).
rm_even_odd([A|L],[A|R],Flag):- rm_even_odd(L,R,Flag).

/* 2015.2.23 End */

%%%%
clp_set([],_):-!.
clp_set([V|L],Clause):- var(V),!,freeze(V,Clause), clp_set(L,Clause).
clp_set([V|L],Clause):- clp_set(L,Clause).

clp_all_1([]):-!.
clp_all_1([1|L]):- clp_all_1(L).
%%%
get_min_max([A..B|L],A,C):- !,get_max(L,B,C).
get_min_max([A|L],A,B):- integer(A),!,get_max(L,A,B).
get_min_max([_|L],A,C):- get_min_max(L,A,C).

get_max([C..D|L],_,B):- !,get_max(L,D,B).
get_max([C|L],_,B):- integer(C),!,get_max(L,C,B).
get_max(_,A,A):-!.

%%%%%%%%%%%%%%%%%%%%
%%  Non Keisu (Mahojin Type)
:- public '$clp_area_propagation3' /2.
'$clp_area_propagation3'(Num,Vars):-
	clp_value_check3(Num,Vars,0,SMin,0,SMax,VarL,0),
	clp_get_new_area_top3(VarL,SMin,SMax).

%%%%             +   +     +    -    +    -    +  +
clp_value_check3(Num,[],   IMin,OMin,IMax,OMax,[],Flag):-
	!, ( Flag==0 -> Num = 0 ; true ), OMin is Num-IMax,OMax is Num-IMin.
clp_value_check3(Num,[V|L],IMin,OMin,IMax,OMax,[V,Min,Max|VList],_):-
	var(V),!, get_clp_area(V,Area),get_min_max(Area,Min,Max),
	SMin is IMin+Min,SMax is IMax+Max,
	clp_value_check3(Num,L,SMin,OMin,SMax,OMax,VList,1). 
clp_value_check3(Num,[V|L],IMin,OMin,IMax,OMax,VList,Flag):- 
	Num2 is Num-V, clp_value_check3(Num2,L,IMin,OMin,IMax,OMax,VList,Flag). 
%%%
clp_get_new_area_top3([],_,_):- !.
clp_get_new_area_top3([V,A,B|VL],SMin,SMax):-
	Min is SMin+B, Max is SMax+A,
%	V in Min..Max,
	put_clp_area(V,[Min..Max]),
	clp_get_new_area_top3(VL,SMin,SMax).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
:- public '$clp_area_propagation2' /2.

'$clp_area_propagation2'(Num,Vars):-
	clp_value_check2(Num,OutNum,Vars,VarX,Areas),
	length(VarX,Vol),
	(Vol==0 -> OutNum=0;true),
	clp_get_new_area_top2(VarX,Vol,OutNum,Areas).

%%%%            +   -     +      -    
clp_value_check2(Num,Num, [],   [],   L-L):-!.
clp_value_check2(Num,NumO,[V|L],[V|X],[FArea|KsO]-T):-
	var(V),!,get_clp_area(V,Area),
	clp_flat(Area,FArea),
	clp_value_check2(Num,NumO,L,X,KsO-T). 
clp_value_check2(Num,NumO,[V|L],X,R):- 
	Num2 is Num-V,clp_value_check2(Num2,NumO,L,X,R). 
%%%
clp_get_new_area_top2([],   Vol,Num,_):-!. 
clp_get_new_area_top2([V|S],Vol,Num,[K|Vars]-[T|T2]):-
        clp_get_new_area_2(Vol,Num,K,Vars,T),
	T \== [],
	put_clp_area(V,T),
	clp_get_new_area_top2(S,Vol,Num,Vars-T2).
	
clp_get_new_area_2(1,  Num,Area,_,  [Num]):- !,member(Num,Area),!.
clp_get_new_area_2(Vol,Num,Area,KAL,[N|R]):-
        clp_member_2(N,Area,Else),
	Num2 is Num-N,
        Vol2 is Vol-1,
        clp_get_new_area3(Vol2,Num2,KAL),
        !,clp_get_new_area_2(Vol,Num,Else,KAL,R).
clp_get_new_area_2(_,_,_,_,[]).

clp_member_2(N,[N|L],L).
clp_member_2(N,[_|L],R):- clp_member_2(N,L,R).
*/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- public '$clp_area_propagation' /3.

%%% '$clp_area_propagation'(+式の値,+係数List,+変数List).
%%% EX. '$clp_area_propagation'(15,[1,1,1],[X1,X2,X3])  <== 15#=X1+X2+X3
'$clp_area_propagation'(Num,Ks,Vars):-
	clp_value_check(Num,OutNum,Ks,Vars,VarX,Varsout-VL),
	length(VarX,Vol),
	(Vol == 0 -> OutNum=0;true),
	clp_get_new_area_top(VarX,Vol,OutNum,Varsout-VL).

%%%%           Sum  Rest Keisu  Vars        [V/KList]-Tail
%%%%            +   -    +      +      -    
clp_value_check(Num,Num, [],    [],   [],   S-S):-!.
clp_value_check(Num,NumO,[K|Ks],[V|L],[V|X],[K/FArea|KsO]-S):-
	var(V),!,get_clp_area(V,Area),
	clp_flat(Area,FArea),
	clp_value_check(Num,NumO,Ks,L,X,KsO-S). 
clp_value_check(Num,NumO,[K|Ks],[V|L],X,R):- 
	Num2 is Num-K*V,clp_value_check(Num2,NumO,Ks,L,X,R). 
%%
clp_flat([A .. B|L],R):- !,clp_gen_num(A,B,R,R2),clp_flat(L,R2).
clp_flat([A|L],[A|R]):- !,clp_flat(L,R).
clp_flat([],[]).

clp_gen_num(A,A,[A|L],L):-!.
clp_gen_num(A,B,[A|L],R):- AA is A+1,clp_gen_num(AA,B,L,R).
%%
clp_get_new_area_top([],Vol,Num,_):-!. 
clp_get_new_area_top([V|S],Vol,Num,[K/Area|Vars]-[TT|T2]):-
        clp_get_new_area(Vol,Num,K,Area,Vars,T,TT),
	T \== [],
	(var(V) -> put_clp_area(V,T) ;member(V,T),!),
	clp_get_new_area_top(S,Vol,Num,Vars-T2).
	
clp_get_new_area(1,Num,  K,Area,_,[N],[Num]):-
        !,member(N,Area),Num is N*K,!.
clp_get_new_area(Vol,Num,K,Area,KAL,[N|R],[NK|R2]):-
        clp_member2(N,K,Area,Else,NK),
	Num2 is Num-NK,
        Vol2 is Vol-1,
        clp_get_new_area2(Vol2,Num2,KAL),
        !,clp_get_new_area(Vol,Num,K,Else,KAL,R,R2).
clp_get_new_area(_,_,_,_,_,[],[]).

clp_get_new_area2(Vol2,Num2,[K/A|L]):-
	!,clp_get_new_area(Vol2,Num2,K,A,L,X,_),X \==[].
clp_get_new_area2(Vol2,Num2,KAL):-
	clp_get_new_area3(Vol2,Num2,KAL).

clp_get_new_area3(1,Num,[L|_]):- !,member(Num,L),!.
clp_get_new_area3(Vol2,Num2,[KAL|L]):-
	member(Sum,KAL),Num3 is Num2-Sum,
	Vol3 is Vol2-1,
	clp_get_new_area3(Vol3,Num3,L),!.

clp_member2(N,K,[N|L],L,NK):- NK is N*K.
clp_member2(N,K,[_|L],R,NK):- clp_member2(N,K,L,R,NK).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ?- clp_form(X*100-Y*10+4,Num,K,Vars  %%
%%  Num=4,K=[-100,10:,Vars=[X,Y]        %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clp_form(X,NumAA,Ks2,Vars) :- 
	simp(X,Y,V-V,VarsOrg-[]),
	zero(Y,Z),
	clp_ks(Z,VarsOrg,Vars,Ks,Num),
	NumA is -1*Num,
	check_clp_form(NumA,NumAA1,Ks,Ks1),
/* 2015.2.20 */
	check_clp_form2(NumAA1,NumAA,Ks1,Ks2).

check_clp_form2(NumA1,NumAA,Ks1,Ks2):-
	system_get_min_max_int(_,Max),min_ks(Ks1,Max,Min),Min>1,
	0 is NumA1 mod Min,
	ks_can_div(Ks1,Ks2,Min),
	!,NumAA is integer(NumA1 / Min).
check_clp_form2(NumA,NumA,Ks,Ks).

ks_can_div([],[],_):-!.
ks_can_div([Ks1|Ks1L],[Ks2|Ks2L],Min):-
	0 is Ks1 mod Min,Ks2 is integer(Ks1/Min),
	ks_can_div(Ks1L,Ks2L,Min).

min_ks([],M,M):-!.
min_ks([A|L],M,Min):- AbsMin is abs(A),AbsMin<M,!,min_ks(L,AbsMin,Min).
min_ks([_|L],M,Min):- min_ks(L,M,Min).
/* 2015.2.20 */

check_clp_form(NumA,NumA,Ks,Ks):- NumA >=0,!.
check_clp_form(NumA,NumAA,Ks,KsA):- NumAA is -1*NumA,rev_ks(Ks,KsA).

rev_ks([],[]):-!.
rev_ks([A|L],[B|R]):- B is -1*A,rev_ks(L,R).

clp_ks([Num,K],   [V],  [V],  [K],   Num):- integer(Num),!.
clp_ks([[Vars,K]],[V|L],R,    Ks,    Num):-!,clp_ks([Vars,K],L,R,Ks,Num).
clp_ks([Vars,K],  [V|L],[V|R],[K|Ks],Num):-!,clp_ks(Vars,L,R,Ks,Num).

clp_ks(0,  [],[],[],0).		  /* 2015.2.20 */

  %%%%%
zero([],0) :- !.
zero(X,X) :- integer(X),!.
zero([X|Xs],Y) :- zero(X,X1),zero(Xs,Z),zero1(X1,Z,Y).

zero1(0,0,0) :- !.
zero1(X,0,[X]) :- !.
zero1(X,Y,[X|Y]).
  %%%%%
simp(X,X,V,V) :- integer(X),!.
simp(X,Y,V,OV) :- var(X),!,rep(X,Y,V,OV).
simp(T1+T2,X,V,OV) :- !,simp(T1,S1,V,V1),simp(T2,S2,V1,OV),plus(S1,S2,X).
simp(T1-T2,X,V,OV) :- !,simp(T1,S1,V,V1),simp(T2,S2,V1,OV),cmul(-1,S2,S3),plus(S1,S3,X).
simp(T1*T2,X,V,OV) :- !,simp(T1,S1,V,V1),simp(T2,S2,V1,OV),time(S1,S2,X).
simp(T1^T2,X,V,OV) :- !,simp(T1,S1,V,V1),simp(T2,S2,V1,OV),expt(S1,S2,X).

plus(X,Y,Z) :- integer(X),integer(Y),!,Z is X+Y.
plus(X,Y,Z) :- integer(X),!,plus([X],Y,Z).
plus(X,Y,Z) :- integer(Y),!,plus(X,[Y],Z).
plus([],Y,Y) :- !.
plus(X,[],X) :- !.
plus([X|Xs],[Y|Ys],[Z|Zs]) :- plus(X,Y,Z),plus(Xs,Ys,Zs).

cmul(0,X,0) :- !.
cmul(1,X,X) :- !.
cmul(C,X,Z) :- integer(X),!,Z is C*X.
cmul(C,[],[]) :- !.
cmul(C,[X|Xs],[Z|Zs]) :- cmul(C,X,Z),cmul(C,Xs,Zs).

time(X,Y,Z) :- integer(X),!,cmul(X,Y,Z).
time(X,Y,Z) :- integer(Y),!,cmul(Y,X,Z).
time([],Y,[]) :- !.
time([X|Xs],Y,Z) :- time1(Y,X,Y1),time(Xs,[0|Y],Z1),plus(Y1,Z1,Z).

time1([],C,[]) :- !.
time1([X|Xs],C,[Y|Ys]) :- time(X,C,Y),time1(Xs,C,Ys).

expt(X,0,1) :- !.
expt(X,1,X) :- !.
expt(X,N,Z) :- N1 is N-1,expt(X,N1,Z1),time(X,Z1,Z).
%%%%
rep(X,Y,Vars-T,Vars-T) :- vars(X,Vars,1,N),!,rep1(N,Y).
rep(X,Y,Vars-[X|Otail],Vars-Otail) :- length(Vars,N1), rep1(N1,Y).

vars(X,Var,_,_):- var(Var),!,fail.
vars(X,[V|_],N,N):- X==V,!.
vars(X,[_|L],N,O):- NN is N+1,vars(X,L,NN,O). 

rep1(1,[0,1]) :- !.
rep1(N,[X]) :- N1 is N-1,rep1(N1,X).

%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  ?- X in 0..9.    ?-X :: 0..9.  ?- X in [a,b,c]. %%
%%  ?- X notin 0..9. ?- X notin [a,b,c].            %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- public '::' /2.
'::'(X,Y):- in(X,Y).

:- public in /2.

in(List,Y):- list(List),!,clp_incheck(Y,YL),sub_in(List,YL).
in(Var,Y):- clp_incheck(Y,YL),sub_in2(Var,YL).

sub_in2(Var,Y):- var(Var),!,put_clp_area(Var,Y).
sub_in2(X,[A..B]):- integer(X),!,A=<X,X=<B.
sub_in2(X,Y):- clp_is_member(X,Y).

sub_in([],_):-!.
sub_in([A|List],Y):- sub_in2(A,Y),sub_in(List,Y).

clp_incheck(A,B):-list(A),!,clp_sort(A,B).
clp_incheck(Var,_):- var(Var),!,error(9).
clp_incheck(A..B,[A..B]):-A<B,!.
clp_incheck(A..A,[A]):-integer(A),!.

:- public notin /2.

notin(List,Y):- list(List),!,clp_incheck(Y,YL),sub_notin(List,YL).
notin(Var,Y):- clp_incheck(Y,YL),sub_notin2(Var,YL).

sub_notin2(Var,Y):- 
	get_clp_area(Var,Area),!,
	rm_clp_areas(Y,Area,NewA),NewA \==[],put_clp_area(Var,NewA).

sub_notin2(X,[A..B]):- nonvar(X),!,(A>X;X>B),!.
sub_notin2(X,Y):- nonvar(X),!,\+(clp_is_member(X,Y)),!.
sub_notin2(X,Y):- freeze(X,\+clp_is_member(X,Y)).

sub_notin([],_):-!.
sub_notin([A|List],Y):- sub_notin2(A,Y),sub_notin(List,Y).

:- extern det:rm_area/3.
:- public rm_clp_areas/3.
rm_clp_areas([],X,X):-!.
rm_clp_areas([A|L],X,Ans):- rm_area(X,A,X1),rm_clp_areas(L,X1,Ans).

%%%%%%%%%%%%%%%%%%%%%%%%%
:- public clp_sort/2.

clp_sort(L,FS):- 
	clp_sort2(L,Float,Int,PP,Else),
	clp_sort0(Float,Tail,FS),
	clp_sort0(Else,[],ES), 
	clp_sort0(Int,[],IS),
	sortI(IS,ISA,PP),
	clp_sort0(ISA,[],PS),
	clp_sort3(PS,Tail,ES).

clp_sort0([],L1,L1):-!.
clp_sort0([X|L],L1,L2):-
	clp_div(X,L,L3,L4),clp_sort0(L4,L1,L5),clp_sort0(L3,[X|L5],L2).

clp_div(X,[],[],[]):-!.
clp_div(X,[A|L],L1,[A|L2]):-X@<A,!,clp_div(X,L,L1,L2).
clp_div(X,[A|L],L1,L2):-X==A,!,clp_div(X,L,L1,L2).
clp_div(X,[A|L],[A|L1],L2):-clp_div(X,L,L1,L2).

%%%
clp_sort2([],[],[],[],[]):-!.
clp_sort2([A|L],[A|F],IT,PT,E):- float(A),!,clp_sort2(L,F,IT,PT,E).
clp_sort2([A|L],FT,[A|I],PT,E):- integer(A),!,clp_sort2(L,FT,I,PT,E).
% clp_sort2([A|L],_,_,_,_):- var(A),!,error(9).
clp_sort2([A..B|L],FT,IT,[A..B|P],E):- !,A=<B,clp_sort2(L,FT,IT,P,E).
clp_sort2([A|L],FT,IT,PT,[A|E]):- clp_sort2(L,FT,IT,PT,E).

 %%%
sortI([],L,L):-!.
sortI([A|L],[A..X|Ans],Tail):-sortI(A,X,L,Ans,Tail).

sortI(X,X,[],L,L):-!.
sortI(A,X,[B|L],Ans,T):- B is A+1,!,sortI(B,X,L,Ans,T).
sortI(A,A,[B|L],[B..X|Ans],T):- sortI(B,X,L,Ans,T).

 %%%
clp_sort3([],L,L):-!.
clp_sort3([A..B|L],Ans,T):-clp_sort3(A,B,L,Ans,T).

clp_sort3(A,A,[],[A|T],T):-!.
clp_sort3(A,B,[],[A..B|T],T):-!.
clp_sort3(A,B,[C..D|L],Ans,T):-                % 1..5 x 2..4
	A=<C,D=<B,!,clp_sort3(A,B,L,Ans,T).
clp_sort3(A,B,[C..D|L],Ans,T):-                % 1..5 x 2..8
	A=<C,C=<B+1,!,clp_sort3(A,D,L,Ans,T).
clp_sort3(A,A,[C..D|L],[A|Ans],T):-            % 1..5 x 7..8
	!,clp_sort3(C,D,L,Ans,T).              % 2014.1.22 Cut Added
clp_sort3(A,B,[C..D|L],[A..B|Ans],T):-         % 1..5 x 7..8
	clp_sort3(C,D,L,Ans,T).
%%%

:- public #>= /2.
:- public #>  /2.
:- public #=< /2.
:- public #<  /2.
:- public #\= /2.

X #>= I:-var(X),integer(I),!,system_get_min_max_int(_,M),put_clp_area(X,[I..M]).
X #>= Y :- freeze(X,(integer(X),freeze(Y,(integer(Y),X>=Y)))),!.

X #>  I:-var(X),integer(I),!,system_get_min_max_int(_,M),I2 is I+1,put_clp_area(X,[I2..M]).

X #> Y :- freeze(X,(integer(X),freeze(Y,(integer(Y),X>Y)))),!.

%%%
X #=< I:-var(X),integer(I),!,system_get_min_max_int(M,_),put_clp_area(X,[M..I]).
X #=< Y :- freeze(X,(integer(X),freeze(Y,(integer(Y),X=<Y)))),!.

X #<  I:-var(X),integer(I),!,system_get_min_max_int(M,_),I2 is I-1,put_clp_area(X,[M..I2]).

X #< Y :- freeze(X,(integer(X),freeze(Y,(integer(Y),X<Y)))),!.

%%%
#\=(Var,I):- rm_clp_area(Var,I),!.
#\=(Var,I):- freeze(Var,Var\==I).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% SOURCE OF outof/3,clp_intersection/3,rm_clp_area/2 clp_is_member/2 %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
%%%%%%%%%%%%%%%%%
:- public outof/3.  % OLD
%%%%%%%%%%%%%%%%%
outof(A,Before,After):- clp_notmember(A,Before),clp_notmember(A,After).

clp_notmember(A,[]):- !.
clp_notmember(A,[B|L]):- var(B),!,rm_clp_area(B,A),clp_notmember(A,L).
clp_notmember(A,[B|L]):- A \==B,clp_notmember(A,L).

%%%%%%%%%%%%%%%%%%%%%%%%%
:- public rm_clp_area/2.
%%%%%%%%%%%%%%%%%%%%%%%%%

rm_clp_area(A,Int):-
        get_clp_area(A,Area),rm_area(Area,Int,New),put_clp_area(A,New).

%%%%
rm_area( [],I,[]):-!.           % No Contents in domain
rm_area( [I|L],I,L):-!.         % rm_area([4,6,8],6,X)    X=[4,8]
rm_area( [N .. M|L],I,SL):-     % rm_area([1..9,13],5,X). X=[1..4,6..9,13]
        integer(I), N=<I,I=<M,!,
        NN is I-1,MM is I+1,
        rm_area2(N,NN,SL,E),
        rm_area2(MM,M,E,L).
rm_area( [N..M|L],A..B,Ans):- rm_area_pp(L,N,M,A,B,Ans),!.
rm_area( [S|L],   A..B,Ans):- integer(S),rm_area_p(L,S,A,B,Ans),!.
rm_area( [S|L],I,[S|R]):-rm_area(L,I,R).

%%%  Area X Integer
rm_area2(N,N,[N|L],L):-!.              % 1..X,2  (1,3) ==> [1|L] ==> [1,3]
rm_area2(N,M,L,L):-N>M,!.              % 1..X,1  (0,2) ==> L     ==>  L
rm_area2(N,M,[N,M|L],L):- M is N+1,!.  % 1..X,3  (2,4) ==> [1,2,4..X]
rm_area2(N,M,[N .. M|L],L).            % 1..X,4  (3,5) ==> [1..3,5..X]

%%% Integer X Area
rm_area_p(_, I, A,_, _):- I<A,!,fail.                    % [3|L], 4..8
rm_area_p(L, I, _,B,[I|L]):- I>B,!.                      % [5|L], 0..4
rm_area_p(L, I, _,I,L):-!.                               % [5|L], 0..5
rm_area_p(L, I, A,B,R):- A=<I,I<B,rm_area(L,A..B,R).     % [5|L], 3..7

%%% Area X Area L,N..M,A..B
rm_area_pp(_,_,M, A,_,_):- M<A,!,fail.                  % [1..4|L],5..6
rm_area_pp(L,N,M, I,B,SL):- N>B,!,rm_area2(N,M,SL,L).   % [4..6|L],0..3
rm_area_pp(L,N,M, I,J,SL):- I=<N,J<M,!,K is J+1,rm_area2(K,M,SL,L).
                                                        % [3..6|L],2..4
rm_area_pp(L,N,M, I,J,SL):-                             % [2..8|L],4..5
% 12.3 % I>N,J<M,!,Q is I-1,R is J+1,rm_area2(N,Q,SL,E),rm_area2(R,M,E,L).
        I>N,J=<M,!,Q is I-1,R is J+1,rm_area2(N,Q,SL,E),rm_area2(R,M,E,L).
rm_area_pp(L,N,M, I,J,SL):-                             % [2..4|L],3..5
        I>N, J>M,!,Q is I-1,rm_area2(N,Q,SL,R),rm_area(L,I..J,R).
rm_area_pp(L,N,M, I,J,R):-                              % [2..4|L],1..5
        I=<N, J>M,!,rm_area(L,I..J,R).

%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public clp_intersection/3.
%%%%%%%%%%%%%%%%%%%%%%%%%%

% | ?-put_clp_area(X,[1.2,3..8,10..11,b,c]),put_clp_area(X,[-100,5]).
% X       = 5,

clp_intersection([],_,[]) :- !.
clp_intersection(_,[],[]) :- !.
clp_intersection([A..B|L],[C..D|R],Ans) :-
        !,clp_intersec2(A,B,NewL,L, C,D,NewR,R, Ans,T),
        clp_intersection(NewL,NewR,T).
clp_intersection([A|L],[C..D|R],Ans) :-
        !,clp_intersec3(A,NewL,L, C,D,NewR,R, Ans,T),
        clp_intersection(NewL,NewR,T).
clp_intersection([A..B|L],[C|R],Ans) :-
        !,clp_intersec3(C,NewR,R,A,B,NewL,L,Ans,T),
        clp_intersection(NewL,NewR,T).
clp_intersection([C|L],[C|R],[C|Ans]) :- !,clp_intersection(L,R,Ans).
clp_intersection([A|L],[C|R],Ans) :- A@<C,!,clp_intersection(L,[C|R],Ans).
clp_intersection([A|L],[C|R],Ans) :- clp_intersection([A|L],R,Ans).

%% IntegerArea X IntegerArea
clp_intersec2(A,B,L, L,       C,D,[C..D|R],R,T,T):-B<C,!.
clp_intersec2(A,B,[A..B|L],L, C,D,R,R,       T,T):-D<A,!.
clp_intersec2(A,B,LL,L,       C,D,RR,R,      S,T):-
        clp_upper(A,C,E),clp_lower(B,D,F,LL,L,RR,R),
        clp_mk_pp(E,F,S,T),!.

clp_upper(A,C,A):- A>=C,!.
clp_upper(A,C,C).

clp_lower(B,D,B,L,L, RR,R):- B=<D,!,BB is B+1,clp_mk_pp(BB,D,RR,R).
clp_lower(B,D,D,LL,L,R,R) :- DD is D+1,clp_mk_pp(DD,B,LL,L).

clp_mk_pp(A,B,T,T):- A>B,!.
clp_mk_pp(A,A,[A|T],T):- !.
clp_mk_pp(A,B,[A,B|T],T):- B is A+1,!.
clp_mk_pp(A,B,[A..B|T],T).

%% Integer X IntegerArea
clp_intersec3(A,L,L,     C,D,[C..D|R],R, T,T):- (float(A);A<C),!.
clp_intersec3(A,[A|L],L, C,D,R,R,        T,T):- ( \+ integer(A);A>D),!.
clp_intersec3(A,L,L,     C,D,RR,R,       [A|T],T):-
        AA is A+1,clp_mk_pp(AA,D,RR,R),!.

%%%%%%%%%%%%%%%%%%%%%%%%%%
:- public clp_is_member/2
%%%%%%%%%%%%%%%%%%%%%%%%%%

clp_is_member(X,[Y|_]):- \+(\+(X=Y)),!.
clp_is_member(X,[A..B|L]):- integer(X),X>=A,X=<B,!.
clp_is_member(X,[_|L]):- clp_is_member(X,L).

*/

:- s_mode(_,off).

