diff options
author | elioat <{ID}+{username}@users.noreply.github.com> | 2024-07-16 13:58:44 -0400 |
---|---|---|
committer | elioat <{ID}+{username}@users.noreply.github.com> | 2024-07-16 13:58:44 -0400 |
commit | b6e8a9bfd57ad64453518c76357f4006ba6e13c3 (patch) | |
tree | 6a441a7a87a7a0313d1fdb774b1aabc714a09f11 /picat/exs.pi | |
parent | 999ec94e90772456f487dbc858e950884ec01c65 (diff) | |
download | tour-b6e8a9bfd57ad64453518c76357f4006ba6e13c3.tar.gz |
*
Diffstat (limited to 'picat/exs.pi')
-rw-r--r-- | picat/exs.pi | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/picat/exs.pi b/picat/exs.pi new file mode 100644 index 0000000..17f8083 --- /dev/null +++ b/picat/exs.pi @@ -0,0 +1,594 @@ +/* Several examples in Picat */ +/**** begin file exs.pi ****/ +import cp, planner. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% PREDICATES AND FUNCTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Here are several versions for computing Fibonacci numbers +% A predicate +fibp(0,F) => F = 1. +fibp(1,F) => F = 1. +fibp(N,F),N>1 => fibp(N-1,F1), fibp(N-2,F2), F = F1+F2. + +% A function +fibf(0)=F => F = 1. +fibf(1)=F => F = 1. +fibf(N)=F, N>1 => F = fibf(N-1)+fibf(N-2). + +% A function with function facts +fibfa(0) = 1. +fibfa(1) = 1. +fibfa(N) = fibfa(N-1)+fibfa(N-2). + +% Using if-then-else +fibi(N) = F => + if N == 0 then + F = 1 + elseif N == 1 then + F = 1 + else + F = fibg(N-1)+fibg(N-2) + end. + +% Using Prolog-style if-then-else +fibg(N) = F => + (N == 0 -> + F = 1 + ;N == 1 -> + F = 1 + ; + F = fibg(N-1)+fibg(N-2) + ). + +% Using a conditional expression +fibc(N) = cond((N == 0; N == 1), 1, fibc(N-1)+fibc(N-2)). + +% A tabled function +table +fibt(0) = 1. +fibt(1) = 1. +fibt(N) = fibt(N-1)+fibt(N-2). + +% A nondeterministic predicate with a backtrackable rule +my_member(Y,[X|_]) ?=> Y = X. +my_member(Y,[_|L]) => my_member(Y,L). + +my_between(From,To,X), From == To => X = From. +my_between(From,To,X),From < To => X = From; my_between(From+1,To,X). + +my_select(Y,[X|L],LR) ?=> Y = X, LR = L. +my_select(Y,[X|L],LR) => LR = [X|LRR], my_select(Y,L,LRR). + +my_permutation([],P) => P = []. +my_permutation(L,P) => + P = [X|PR], + my_select(X,L,LR), + my_permutation(LR,PR). + +% predicate facts +index(+,-) (-,+) +edge(1,2). +edge(1,3). +edge(2,3). +edge(3,2). + +% several sort algorithms +merge_sort([]) = []. +merge_sort([X]) = [X]. +merge_sort(L) = SL => split(L,L1,L2), SL = merge(merge_sort(L1),merge_sort(L2)). + +split([X,Y|Zs],L1,L2) => L1 = [X|LL1], L2 = [Y|LL2], split(Zs,LL1,LL2). +split(Zs,L1,L2) => L1 = Zs,L2 = []. + +merge([],Ys) = Ys. +merge(Xs,[]) = Xs. +merge([X|Xs],Ys@[Y|_]) = [X|Zs], X < Y => Zs = merge(Xs,Ys). % Ys@[Y|_] is an as-pattern +merge(Xs,[Y|Ys]) = [Y|Zs] => Zs = merge(Xs,Ys). + +insert_sort([]) = []. +insert_sort([H|T]) = insert(H,insert_sort(T)). + +private +insert(X,[]) = [X]. +insert(X,Ys@[Y|_]) = Zs, X =< Y => Zs = [X|Ys]. +insert(X,[Y|Ys]) = [Y|insert(X,Ys)]. + +% two versions that return the minumum and maximum of a list +% a predicate +min_max_p([H|T],Min,Max) => min_max_p_aux(T,H,Min,H,Max). + +% A private function is not visiable outside +private +min_max_p_aux([],CMin,Min,CMax,Max) => CMin = Min,CMax = Max. +min_max_p_aux([H|T],CMin,Min,CMax,Max) => min_max_p_aux(T,min(CMin,H),Min,max(CMax,H),Max). + +% a function that returns the minimum and maximum of a list as a pair +min_max([H|T]) = min_max_aux(T,H,H). + +private +min_max_aux([],CMin,CMax) = (CMin,CMax). +min_max_aux([H|T],CMin,CMax) = min_max_aux(T,min(CMin,H),max(CMax,H)). + +% return the sum of a list +sum_list(L) = Sum => + sum_list_aux(L,0,Sum). + +% a private predicate is never exported +private +sum_list_aux([],Acc,Sum) => Sum = Acc. +sum_list_aux([X|L],Acc,Sum) => sum_list_aux(L,Acc+X,Sum). + +% two lists that are structually equal, e.g., struct_equal(X,[a]) fails +struct_equal(A,B),atomic(A) => A == B. +struct_equal([H1|T1],[H2|T2]) => + struct_equal(H1,H2), + struct_equal(T1,T2). + +is_sorted([]) => true. +is_sorted([_]) => true. +is_sorted([X|L@[Y|_]]) =>X @<= Y, is_sorted(L). + +% An empty tree is represented by {}, and a non-empty binary tree is +% represented by its root, which takes form {Val,Left,Right}. + +is_btree({}) => true. +is_btree({_Val,Left,Right}) => + is_btree(Left), + is_btree(Right). + +inorder({}) = []. +inorder({Val,Left,Right}) = inorder(Left) ++ [Val] ++ inorder(Right). + +% binary search tree +is_bstree({}) => true. +is_bstree(BT@{Val,Left,Right}) => + is_bstree(Left,min_bstree(BT),Val), + is_bstree(Right,Val,max_bstree(BT)). + +is_bstree({},_,_) => true. +is_bstree({Val,Left,Right},Min,Max) => + Val @>= Min, Val @=< Max, + is_bstree(Left,Min,Val), + is_bstree(Right,Val,Max). + +min_bstree({Elm,{},_Right}) = Elm. +min_bstree({_Elm,Left,_Right}) = min_bstree(Left). + +max_bstree({Elm,_Left,{}}) = Elm. +max_bstree({_Elm,_Left,Right}) = max_bstree(Right). + +lookup_bstree({Elm,_,_},Elm) => true. +lookup_bstree({Val,Left,_},Elm), Elm < Val => + lookup_bstree(Left,Elm). +lookup_bstree({_,_,Right},Elm) => + lookup_bstree(Right,Elm). + +tree_inst1 = {6, {5, {4, {}, {}}, + {7, {}, {}}}, + {8, {3, {}, {}}, + {9, {}, {}}}}. + +tree_inst2 = {7, {5, {4, {}, {}}, + {6, {}, {}}}, + {8, {8, {}, {}}, + {9, {}, {}}}}. + +test_btree => + Tree1 = tree_inst1(), + println(inorder(Tree1)), + println(cond(is_bstree(Tree1),"a binary search tree","not a binary search tree")), + Tree2 = tree_inst2(), + println(inorder(Tree2)), + println(cond(is_bstree(Tree2),"a binary search tree","not a binary search tree")). + +% An example that uses data constructors +% A term in the form of $f(X) is a data constructor +divide_main => + Exp= $((((((((x/x)/x)/x)/x)/x)/x)/x)/x)/x, + d(Exp,x,D), + writeln(D). + +d(U+V,X,D) => + D = $DU+DV, + d(U,X,DU), + d(V,X,DV). +d(U-V,X,D) => + D = $DU-DV, + d(U,X,DU), + d(V,X,DV). +d(U*V,X,D) => + D = $DU*V+U*DV, + d(U,X,DU), + d(V,X,DV). +d(U/V,X,D) => + D = $(DU*V-U*DV)/(^(V,2)), + d(U,X,DU), + d(V,X,DV). +d(^(U,N),X,D) => + D = $DU*N*(^(U,N1)), + integer(N), + N1 = N-1, + d(U,X,DU). +d(-U,X,D) => + D = $-DU, + d(U,X,DU). +d(exp(U),X,D) => + D = $exp(U)*DU, + d(U,X,DU). +d(log(U),X,D) => + D = $DU/U, + d(U,X,DU). +d(X,X,D) => D=1. +d(_,_,D) => D=0. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% LOOPS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% another version for summing up a list +sum_list_imp(L) = Sum => + S = 0, + foreach (X in L) + S := S+X + end, + Sum = S. + +% using a loop to find the minimum and maximum of a list +min_max_ip([H|T], Min, Max) => + LMin = H, + LMax = H, + foreach (E in T) + LMin := min(LMin, E), + LMax := max(LMax, E) + end, + Min = LMin, + Max = LMax. + +% draw the Pascal triangle +pascal => + print("enter an integer:"), + N = read_int(), + foreach(I in 0..N) + Num := 1, + foreach(K in 1..I+1) + printf("%d ",Num), + Num := Num*(I-K+1) div K + end, + nl + end. + +% another solution +pascal2 => + print("enter an integer:"), + N = read_int(), + Row = [1], + foreach(_I in 1..N) + writeln(Row), + Row := next_row(Row) + end. + +private +next_row(Row)=Res => + NewRow = [1], Prev = 1, + foreach (K in tail(Row)) + NewRow := [Prev+K|NewRow], + Prev := K + end, + Res = [1|NewRow]. + +/* another definition, not so efficient because Row[I] takes O(I) time +private +next_row(Row) = [1] ++ [Row[I]+Row[I+1] : I in 1..Row.length-1] ++ [1]. +*/ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% LIST COMPREHENSION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% a list comprehension inside another list comprehension +% Picat> L=list_of_lists(5) +% L = [[1],[1,2] [1,2,3],[1,2,3,4],[1,2,3,4,5]] +list_of_lists(N) = [[Y : Y in 1..X] : X in 1..N]. + +% another definition +another_list_of_lists(N) = [1..X : X in 1..N]. + +qsort([]) = []. +qsort([H|T]) = qsort([E : E in T, E =< H])++[H]++qsort([E : E in T, E>H]). + +power_set([]) = [[]]. +power_set([H|T]) = P1++P2 => + P1 = power_set(T), + P2 = [[H|S] : S in P1]. + +% generate permutations +perm([]) = [[]]. +perm(Lst) = [[E|P] : E in Lst, P in perm(Lst.delete(E))]. + +%another definition +perm1([]) = [[]]. +perm1([H|T]) = [insert(P,I,H) : P in Ps, I in 1..P.length+1] => Ps = perm1(T). + +% A*B=C +matrix_multi(A,B) = C => + 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. + +% Sieve of Eratosthenes +my_primes(N) = L => + A = new_array(N), + foreach(I in 2..floor(sqrt(N))) + if (var(A[I])) then + foreach(J in I**2..I..N) + A[J] = 0 + end + end + end, + L = [I : I in 2..N, var(A[I])]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% TABLING +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% mode-directed tabling +% finding shortest paths on a graph given by the relation edge/3. +table(+,+,-,min) +sp(X,Y,Path,W) ?=> + Path=[(X,Y)], + edge(X,Y,W). +sp(X,Y,Path,W) => + Path = [(X,Z)|PathR], + edge(X,Z,W1), + sp(Z,Y,PathR,W2), + W = W1+W2. + +index(+,-,-) (+,+,-) +edge(1,2,1). +edge(1,3,2). +edge(2,3,3). +edge(3,2,4). + +% binomial coefficient +bc(_N,0) = 1. +bc(N,N) = 1. +bc(N,1) = N. +bc(N,K) = bc(N-1,K-1) + bc(N-1,K). + +% computing the minimal editing distance of two given lists +table(+,+,min) +edit([],[],D) => D=0. +edit([X|Xs],[X|Ys],D) => % copy + edit(Xs,Ys,D). +edit(Xs,[_Y|Ys],D) ?=> % insert + edit(Xs,Ys,D1), + D = D1+1. +edit([_X|Xs],Ys,D) => % delete + edit(Xs,Ys,D1), + D = D1+1. + +% the Farmer's problem (use planner) +farmer => + S0 = [s,s,s,s], + plan(S0,Plan), + println(Plan). + +final([n,n,n,n]) => true. + +action([F,F,G,C],S1,Action,ActionCost) ?=> + Action = farmer_wolf, + ActionCost = 1, + opposite(F,F1), + S1 = [F1,F1,G,C], + not unsafe(S1). +action([F,W,F,C],S1,Action,ActionCost) ?=> + Action = farmer_goat, + ActionCost = 1, + opposite(F,F1), + S1 = [F1,W,F1,C], + not unsafe(S1). +action([F,W,G,F],S1,Action,ActionCost) ?=> + Action = farmer_cabbage, + ActionCost = 1, + opposite(F,F1), + S1 = [F1,W,G,F1], + not unsafe(S1). +action([F,W,G,C],S1,Action,ActionCost) => + Action = farmer_alone, + ActionCost = 1, + opposite(F,F1), + S1 = [F1,W,G,C], + not unsafe(S1). + +index (+,-) (-,+) +opposite(n,s). +opposite(s,n). + +unsafe([F,W,G,_C]),W == G,F !== W => true. +unsafe([F,_W,G,C]),G == C,F !== G => true. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% CONSTRAINT PROGRAMS (using cp) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% SEND+MORE=MONEY +sendmory => + Vars = [S,E,N,D,M,O,R,Y], % generate variables + Vars :: 0..9, + all_different(Vars), % generate constraints + S #!= 0, + M #!= 0, + 1000*S+100*E+10*N+D+1000*M+100*O+10*R+E + #= 10000*M+1000*O+100*N+10*E+Y, + solve(Vars), % search + writeln(Vars). + +% N-queens +queens(N) => + Qs = new_array(N), + Qs :: 1..N, + foreach (I in 1..N-1, J in I+1..N) + Qs[I] #!= Qs[J], + abs(Qs[I]-Qs[J]) #!= J-I + end, + solve([ff],Qs), + writeln(Qs). + +% another program for N-queens +queens2(N, Q) => + Q = new_list(N), + Q :: 1..N, + Q2 = [$Q[I]+I : I in 1..N], + Q3 = [$Q[I]-I : I in 1..N], + all_different(Q), + all_different(Q2), + all_different(Q3), + solve([ff],Q). + +% graph coloring (reuse edge/2 defined above) +color(NV,NC) => + A = new_array(NV), + A :: 1..NC, + foreach(I in 1..NV-1, J in I+1..NV) + if edge(I,J);edge(J,I) then + A[I] #!= A[J] + end + end, + solve(A), + writeln(A). + +% a 0-1 integer model for graph coloring +bcolor(NV,NC) => + A = new_array(NV,NC), + A :: [0,1], + foreach(I in 1..NV) + sum([A[I,K] : K in 1..NC]) #= 1 + end, + foreach(I in 1..NV-1, J in I+1..NV) + if edge(I,J);edge(J,I) then + foreach(K in 1..NC) + #~ A[I,K] #\/ #~ A[J,K] + end + end + end, + solve(A), + writeln(A). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% I/O +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Read a list of integers, stopping when 0 is read +read_array_main => + A = new_array(100), + Len = read_array(A), + foreach (I in 1..Len) + writeln(A[I]) + end. + +read_array(A) = Len => + Count = 0, + E = read_int(), % read from stdin + while (E != 0) + Count := Count+1, + A[Count] = E, + E := read_int() + end, + Len = Count. + +% copy a text file line-by-line +copy(IName,OName) => + IStream = open(IName), + OStream = open(OName,write), + Line = IStream.read_line(), + while (Line != end_of_file) + OStream.printf("%s%n",Line), + Line := IStream.read_line() + end, + close(IStream), + close(OStream). + +% Picat> output_students([$student("john","cs",3),$student("mary","math",4.0)]) +% john cs 3.00 +% mary math 4.00 +output_students(Students) => + foreach($student(Name,Major,GPA) in Students) + printf("%10s %10s %5.2f%n",Name,Major,to_real(GPA)) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% HIGHER-ORDER (not recommended because of poor performance) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Picat> my_map(-,[1,2,3]) = L +% L = [-1,-2,-3] +% Picat> my_map(+,[1,2,3],[4,5,6]) = L +% L = [5,6,7] +% Picat> my_fold(+,0,[1,2,3]) = S +% S = 6 + +my_map(_F,[]) = []. +my_map(F,[X|Xs]) = [apply(F,X)|my_map(F,Xs)]. + +my_map(_F,[],[]) = []. +my_map(F,[X|Xs],[Y|Ys]) = [apply(F,X,Y)|my_map(F,Xs,Ys)]. + +my_fold(_F,Acc,[]) = Acc. +my_fold(F,Acc,[H|T]) = my_fold(F, apply(F,H,Acc),T). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% ACTION RULES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +test_ar => + watch_event(X), + watch_dom(X), + watch_dom_any(X), + watch_ins(X), + watch_bound(X), + X.post_event(event), + X.post_event_dom(dom), + X.post_event_ins(), + X.post_event_bound(), + X.post_event_any(any). + +watch_event(X), + {event(X,T)} +=> + writeln($event(T)). + +watch_dom(X), + {dom(X,T)} +=> + writeln($dom(T)). + +watch_dom_any(X), + {dom_any(X,T)} +=> + writeln($dom_any(T)). + +watch_ins(X), + {ins(X)} +=> + writeln($ins(X)). + +watch_bound(X), + {bound(X)} +=> + writeln($bound(X)). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% EXCEPTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +catch_divided_by_zero => + catch(write(myd(4,0)),E, $handle(E)). + +myd(X,Y)=X/Y. + +handle(E) => + writeln(E), + throw(E). % just re-throw it + +/**** end file exs.pi ****/ |