	/* Array procedures */

	/*---------------------------------------------------------*/
	/*                                                         */
	/* An array NL x NC elements is represented as follows :   */
	/* A = [L_1, ..., L_NL] with L_i = [X_i_1, ..., X_i_NC]    */
	/* Hence :                                                 */
	/* A = [ [X_1_1,..., X_1_NC], ..., [X_NL_1,..., X_NL_NC] ] */
	/*---------------------------------------------------------*/

	% create_array(NL,NC,A)
	%     NL: nb of lines   NC:nb of columns   A:array
	%     creates an array (with unbound variables)
 
create_array(NL,NC,A):-
	create_array1(0,NL,NC,A),
	!.


create_array1(NL,NL,_,[]).

create_array1(I,NL,NC,[L|A]):-
	create_one_line(0,NC,L),
	I1 is I+1,
	create_array1(I1,NL,NC,A).




create_one_line(NC,NC,[]).

create_one_line(J,NC,[_|L]):-
	J1 is J+1,
	create_one_line(J1,NC,L).




array_elem(A,I,J,X):-
	nth(I,A,L),
	nth(J,L,X).



array_values([],[]).
array_values([L|A],Values):-
	array_values(A,V),
	append(L,V,Values).




	% for_each_line(A,P)
	%     A:array   P: program atom
	%     calls: array_prog(P,L) for each line L (L is a list)
 
for_each_line([],_).

for_each_line([L|A],P):-
	array_prog(P,L),
	for_each_line(A,P).




	% for_each_column(A,P)
	%     A:array   P: program atom
	%     calls:  array_prog(P,L) for each column L (L is a list)
 
for_each_column([[]|_],_):-
	!.

for_each_column(A,P):-
	create_column(A,C,A1),
	array_prog(P,C),
	for_each_column(A1,P).




create_column([],[],[]).

create_column([[X|L]|A],[X|C],[L|A1]):-
	create_column(A,C,A1).




	% for_each_diagonal(A,NL,NC,P)
	%     A:array   NL: nb of lines   
	%     NC:nb of columns   P: program atom
	%     calls:  array_prog(P,D) for each diagonal D (D is a list)
 
for_each_diagonal(A,NL,NC,P):-
	NbDiag is 2*(NL+NC-1),              % numbered from 0 to NbDiag-1
	create_lst_diagonal(0,NbDiag,LD),
	fill_lst_diagonal(A,0,NL,NC,LD,LD1),
	!,
	for_each_line(LD1,P).




create_lst_diagonal(NbDiag,NbDiag,[]).

create_lst_diagonal(I,NbDiag,[[]|LD]):-
	I1 is I+1,
	create_lst_diagonal(I1,NbDiag,LD).




fill_lst_diagonal([],_,_,_,LD,LD).

fill_lst_diagonal([L|A],I,NL,NC,LD,LD2):-
	I1 is I+1,
	fill_lst_diagonal(A,I1,NL,NC,LD,LD1),
	one_list(L,I,NL,0,NC,LD1,LD2).





one_list([],_,_,_,_,LD,LD).

one_list([X|L],I,NL,J,NC,LD,LD3):-
	J1 is J+1,
	one_list(L,I,NL,J1,NC,LD,LD1),
	NoDiag1 is I+J,
	NoDiag2 is I+NC-J+NL+NC-2,
	add_in_lst_diagonal(0,NoDiag1,X,LD1,LD2),
	add_in_lst_diagonal(0,NoDiag2,X,LD2,LD3).





add_in_lst_diagonal(NoDiag,NoDiag,X,[D|LD],[[X|D]|LD]).

add_in_lst_diagonal(K,NoDiag,X,[D|LD],[D|LD1]):-
	K1 is K+1,
	add_in_lst_diagonal(K1,NoDiag,X,LD,LD1).






	% for_each_big_diagonal(A,N,P)
	%     A:array   N: nb of lines/columns (must be a square)
	%     P: program atom
	%     calls:  array_prog(P,D) for each diagonal D (D is a list)
 

for_each_big_diagonal(A,N,P):-
	big_diags(A,0,N,D1,D2),
	array_prog(P,D1),
	array_prog(P,D2).


big_diags([],_,_,[],[]).

big_diags([L|A],I,J,[X|D1],[Y|D2]):-
	I1 is I+1,
	J1 is J-1,
	nth(I1,L,X),
	nth(J,L,Y),
	big_diags(A,I1,J1,D1,D2).




	% write_array(A,Format,Sep)
	%     A:array   Format: format for element writing
        %     Sep: nb of spaces between 2 elements of a line

write_array([],_,_).

write_array([L|A],Format,Sep):-
	write_array_line(L,Format,Sep),
	nl,
	write_array(A,Format,Sep).


write_array_line([],_,_).

write_array_line([X|L],Format,Sep):-
	format(Format,[X]),
	tab(Sep),
	write_array_line(L,Format,Sep).


	% array_labeling(A)
	%     A:array


array_labeling([]).

array_labeling([L|A]):-
	fd_labeling(L),
	array_labeling(A).
