From 999ec94e90772456f487dbc858e950884ec01c65 Mon Sep 17 00:00:00 2001 From: elioat <{ID}+{username}@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:56:46 -0400 Subject: * --- picat/util.pi | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 picat/util.pi (limited to 'picat/util.pi') diff --git a/picat/util.pi b/picat/util.pi new file mode 100644 index 0000000..6d6b70e --- /dev/null +++ b/picat/util.pi @@ -0,0 +1,294 @@ +/* + Some general utilities in Picat. + Others have been moved to the modules basic, math, sys, etc. + by Hakan Kjellerstrand and Neng-Fa Zhou. +*/ + +module util. + +% array_matrix_to_list(A) = array_matrix_to_list(A). +% array_matrix_to_list_matrix(A) = array_matrix_to_list_matrix(A). +% chunks_of(L,N) = chunks_of(L,N). +% columns(Matrix) = columns(Matrix). +% diagonal1(Matrix) = diagonal1(Matrix). +% diagonal2(Matrix) = diagonal2(Matrix). +% drop(L,N) = drop(L,N). +% find(String, SubString, From, To) => find(String, SubString, From, To). +% find_first_of(Compound,Pattern) = find_first_of(Compound,Pattern). +% find_ignore_case(String, SubString, From, To) => find_ignore_case(String, SubString, From, To). +% find_last_of(Compound,Pattern) = find_last_of(Compound,Pattern). +% join(S) = join(S). +% join(S, Seperator) = join(S, Seperator). +% list_matrix_to_array_matrix(L) = list_matrix_to_array_matrix(L). +% lstrip(L) = lstrip(L," \t\n\r"). +% lstrip(L,Chars) = lstrip(L,Chars). +% matrix_multi(A,B) = matrix_multi(A,B). +% nextto(X,Y,List) => nextto(X,Y,List). +% permutation(Xs,Ys) => permutation(Xs,Ys). +% permutations(Xs) = permutations(Xs). +% power_set(Set) = power_set(Set). +% replace(Term,Old,New) = replace(Term,Old,New). +% replace_at(Compound,I,NewArg) = replace_at(Compound,I,NewArg). +% rows(Matrix) = rows(Matrix). +% rstrip(L) = rstrip(L," \t\n\r"). +% rstrip(L,Chars) = rstrip(L,Chars). +% split(Str) = split(Str). +% split(Str,Seperators) = split(Str,Seperators). +% strip(L) = strip(L," \t\n\r"). +% strip(L,Chars) = strip(L,Chars). +% take(L,N) = take(L,N). +% transpose(Matrix) = transpose(Matrix). + +% +% Convert a 2D array to a list +% +array_matrix_to_list(A) = L => + NRows = A.length, + NCols = A[1].length, + L = [A[I,J] : I in 1..NRows, J in 1..NCols]. + +% Convert a 2D array to a 2D matrix of lists +array_matrix_to_list_matrix(A) = L => + L = [A[I].to_list() : I in 1..A.length]. + +% Convert a 2D list matrix to a 2D array matrix +list_matrix_to_array_matrix(L) = A => + bp.list_matrix_to_array_matrix(L,A). + +% +% Join a list of strings with a join character. +% Res = join(String,JoinChar) +% +join(S) = join(S," "). + +join(S, JoinAtm) = Res, atom(JoinAtm) => + join_aux(S, JoinAtm.to_string(), Res). +join(S,JoinStr) = Res, string(JoinStr) => + join_aux(S,JoinStr,Res). +join(S,JoinStr) = _Res => + handle_exception($string_or_atom_expected(JoinStr), $join(S,JoinStr)). + +private +join_aux([],_JoinStr,Res) => Res = []. +join_aux([W|Str],JoinStr,Res) => + once(append(W,Res1,Res)), + (Str == [] -> + Res2 = Res1 + ; + once(append(JoinStr,Res2,Res1)) + ), + join_aux(Str,JoinStr,Res2). + +%%%% +% replace occurrences of Old in T (a variable or an atomic value) by New +replace(T,Old,New) = Res => + replace_aux(T,Old,New,Res). + +replace_aux(Old,Old,New,Res) => Res = New. +replace_aux(T,Old,New,Res), atomic(T) => Res = T. +replace_aux(T,Old,New,Res), var(T) => Res = T. +replace_aux([H|T],Old,New,Res) => + Res = [NH|NT], + replace_aux(H,Old,New,NH), + replace_aux(T,Old,New,NT). +replace_aux(T,Old,New,Res) => + Res = new_struct(T.name,T.length), + foreach(I in 1 .. T.length) + replace_aux(T[I],Old,New,Res[I]) + end. + +%%%% +% return a copy of the compound value, replacing the Ith argument by NewVal +replace_at(List,I,NewVal) = NewList, integer(I), list(List) => + replace_list_at(List,I,NewVal,NewList,ErrorFlag), + (var(ErrorFlag) -> true; handle_exception($domain_error(I), $replace_at)). +replace_at(Struct,I,NewVal) = NewStruct, integer(I), struct(Struct) => + Arity = len(Struct), + (I >= 1, I =< Arity -> + NewStruct = new_struct(Struct.name,Arity), + foreach(J in 1 .. Arity) + (J == I -> + NewStruct[J] = NewVal + ; + NewStruct[J] = Struct[J] + ) + end + ; + handle_exception($domain_error(I), $replace_at) + ). + +private +replace_list_at([_|List],1,NewVal,NewList,_ErrorFlag) => NewList = [NewVal|List]. +replace_list_at([E|List],I,NewVal,NewList,ErrorFlag) => + NewList = [E|NewList1], + replace_list_at(List,I-1,NewVal,NewList1,ErrorFlag). +replace_list_at(_,_,_,_,ErrorFlag) => ErrorFlag = 1. + +% match a string +% find(String, SubString,From,To) +% +% (If we want to have multiple results it must be a predicate, +% not a function.) +find(String, SubString, From, To) => + SubLen = SubString.length, + bp.append(Pre,SubString,_,String), + From = Pre.length+1, + To = From+SubLen-1. + +% Case insensitive match +find_ignore_case(String, SubString, From, To) => + String2 = String.to_lowercase(), + SubString2 = SubString.to_lowercase(), + find(String2,SubString2,From,To). + +%%%% +% searches for the first argument that unifies with Pattern and returns the argument's index +find_first_of(List,Pattern) = Index, list(List) => + find_list_first_of(List,Pattern,1,Index). +find_first_of(Struct,Pattern) = Index, struct(Struct) => + find_struct_first_of(Struct,Pattern,1, len(Struct), Index). +find_first_of(Struct,_Pattern) = _ => + handle_exception($compound_expected(Struct), find_first_of). + +find_list_first_of([],_Pattern,_CurIndex,Index) => Index = -1. +find_list_first_of([E|L],Pattern,CurIndex,Index), E != Pattern => % not unifiable + find_list_first_of(L,Pattern,CurIndex+1,Index). +find_list_first_of(_L,_Pattern,CurIndex,Index) => Index = CurIndex. + +find_struct_first_of(_Struct,_Pattern,CurIndex,Arity,Index), CurIndex > Arity => Index = -1. +find_struct_first_of(Struct,Pattern,CurIndex,Arity,Index), Struct[CurIndex] != Pattern => % not unifiable + find_struct_first_of(Struct,Pattern,CurIndex+1,Arity,Index). +find_struct_first_of(_,_,CurIndex,_Arity,Index) => Index = CurIndex. + +%%%% +% searches for the last argument that unifies with Pattern and returns the argument's index +find_last_of(List,Pattern) = Index, list(List) => + find_list_last_of(List,Pattern,1,-1,Index). +find_last_of(Struct,Pattern) = Index, struct(Struct) => + find_struct_last_of(Struct,Pattern, len(Struct), Index). +find_last_of(Struct,_) = _ => + handle_exception($compound_expected(Struct), find_last_of). + +find_list_last_of([],_Pattern,_CurIndex,Index0,Index) => Index = Index0. +find_list_last_of([E|L],Pattern,CurIndex,Index0,Index), E != Pattern => % not unifiable + find_list_last_of(L,Pattern,CurIndex+1,Index0,Index). +find_list_last_of([_|L],Pattern,CurIndex,_Index0,Index) => + find_list_last_of(L,Pattern,CurIndex+1,CurIndex,Index). + +find_struct_last_of(_Struct,_Pattern,0,Index) => Index = -1. +find_struct_last_of(Struct,Pattern,CurIndex,Index), Struct[CurIndex] != Pattern => % not unifiable + find_struct_last_of(Struct,Pattern,CurIndex-1,Index). +find_struct_last_of(_,_,CurIndex,Index) => Index = CurIndex. + +% A*B=C +matrix_multi(A,B) = C, array(A), array(B) => % A and B must be array matricies + C = new_array(A.length,B[1].length), + foreach(I in 1..A.length, J in 1..B[1].length) + C[I, J] = sum([A[I,K]*B[K,J] : K in 1..A[1].length]) + end. + +% nondet +permutation(Xs, Ys) => bp.permutation(Xs,Ys). + +% generate permutations +permutations([]) = [[]]. +permutations([H|T]) = [insert(P,I,H) : P in Ps, I in 1..P.length+1] => Ps = permutations(T). + +%nonet +nextto(X,Y, List) => bp.nextto(X,Y,List). + +% generate the power set +power_set([]) = [[]]. +power_set([H|T]) = P1++P2 => + P1 = power_set(T), + P2 = [[H|S] : S in P1]. + +% +% Split a string into tokens given some split chars +% List = split(String, Seperators) +% +split(Str) = split(Str," \t\n\r"). % use white spaces as the default set of separators + +split(Str,Seperators) = Tokens => + bp.picat_split_string(Str,Seperators,Tokens). + +lstrip(L) = lstrip(L," \t\n\r"). + +lstrip([],_Elms) = []. +lstrip([E|L],Elms) = NewL, membchk(E, Elms) => NewL = lstrip(L,Elms). +lstrip(L,_Elms) = NewL => NewL = L. + +rstrip(L) = rstrip(L," \t\n\r"). + +rstrip(L, Elms) = L.reverse().lstrip(Elms).reverse(). + +strip(L) = strip(L," \t\n\r"). + +strip(L, Elms) = L.lstrip(Elms).rstrip(Elms). + +% +% Transpose a 2D matrix +% +transpose(Matrix) = Transposed, array(Matrix) => % array matrix + N = Matrix.length, + M = Matrix[1].length, + Transposed = new_array(M,N), + foreach(I in 1..N, J in 1..M) + Transposed[J,I] = Matrix[I,J] + end. +transpose(Matrix) = Transposed => % assumed to be list matrix + N = Matrix.length, + M = Matrix[1].length, + Transposed = [Mj : J in 1..M, Mj = [Matrix[I,J] : I in 1..N]]. + +%============= +% for matrices (inspired by B-Prolog's ^rows, ^columns, ^diag1, ^diag2) +% +% These should be put in util.pi since transpose/1 is used. + +rows(M) = M, list(M) => true. +rows(A) = Rows, array(A) => NRows = A.length, Rows = [A[I] : I in 1..NRows]. + +columns(M) = [Column : Column in M.transpose()], list(M) => true. +columns(A) = [Column : Column in A.transpose()], array(A) => true. + +diagonal1(M) = [M[I,I] : I in 1..M.length], list(M) => true. +diagonal1(A) = [A[I,I] : I in 1..A.length], array(A) => true. + +diagonal2(M) = [M[I,M.length-I+1] : I in 1..M.length], list(M) => true. +diagonal2(A) = [A[I,A.length-I+1] : I in 1..A.length], array(A) => true. + + +%============= +% from Haskell prelude +% +take(L,N) = Taken, list(L), integer(N), take_aux(L,N,Taken) => true. + +private +take_aux([H|T],N,Taken), N > 0 => Taken = [H|TakenR], take_aux(T,N-1,TakenR). +take_aux(_List,_N,Taken) => Taken = []. + +drop(L,N) = Taken, list(L), integer(N), drop_aux(L,N,Taken) => true. + +private +drop_aux([_|T],N,Taken), N > 0 => drop_aux(T,N-1,Taken). +drop_aux(L,_,Taken), list(L) => Taken = L. + +chunks_of([],_N) = []. +chunks_of(L,N) = Chunks, list(L) => + Chunks = [Chunk|ChunksR], + chunks_of(L,Chunk,0,N,ChunksR). + +chunks_of([],Chunk,_,_,Chunks) => Chunk = [], Chunks = []. +chunks_of(L,Chunk,N,N,Chunks) => + Chunk = [], + (L == [] -> + Chunks = [] + ; + Chunks = [NextChunk|ChunksR], + chunks_of(L,NextChunk,0,N,ChunksR) + ). +chunks_of([X|Xs],Chunk,Count,N,Chunks) => + Chunk = [X|ChunkR], + chunks_of(Xs,ChunkR,Count+1,N,Chunks). + -- cgit 1.4.1-2-gfad0