	/* 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).
