/* Fast MU benchmark in Picat v3. From bench/fast_mu.pl For Picat v3 https://github.com/SWI-Prolog/bench Changes: * changed length/2 to bp.length/2 This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ main => go. go => theorem([m,u,i,i,u]), println(ok), nl. go => true. % This prints an eternal list of solutions go2 => % G = [m,u,i,i,u], GL1 = 4, bp.length(G, GL1), GL is GL1 - 1, derive([m,i], G, 1, GL, Derivation, 0), nl, print_results($[rule(0,[m,i])|Derivation], 0), fail, nl. go2 => true. % % The MU-puzzle % from Hofstadter's "Godel, Escher, Bach" (pp. 33-6). % written by Bruce Holmer % % To find a derivation type, for example: % theorem([m,u,i,i,u]). % Also try 'miiiii' (uses all rules) and 'muui' (requires 11 steps). % Note that it can be shown that (# of i's) cannot be a multiple % of three (which includes 0). % Some results: % % string # steps % ------ ------- % miui 8 % muii 8 % muui 11 % muiiu 6 % miuuu 9 % muiuu 9 % muuiu 9 % muuui 9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% top :- theorem([m,u,i,i,u]). % First break goal atom into a list of characters, % find the derivation, and then print the results. theorem(G) :- bp.length(G, GL1), GL is GL1 - 1, derive([m,i], G, 1, GL, _Derivation, 0). % nl, print_results($[rule(0,[m,i])|Derivation], 0). % derive(StartString, GoalString, StartStringLength, GoalStringLength, % Derivation, InitBound). derive(S, G, SL, GL, D, B) :- % B1 is B + 1, % write('depth '), write(B1), nl, derive2(S, G, SL, GL, 1, D, B). derive(S, G, SL, GL, D, B) :- B1 is B + 1, derive(S, G, SL, GL, D, B1). % derive2(StartString, GoalString, StartStringLength, GoalStringLength, % ScanPointer, Derivation, NumRemainingSteps). derive2(S, S, SL, SL, _, [], _). derive2(S, G, SL, GL, Pin, [rule(N,I)|D], R) :- lower_bound(SL, GL, B), R >= B, R1 is R - 1, rule(S, I, SL, IL, Pin, Pout, N), derive2(I, G, IL, GL, Pout, D, R1). rule([m|T1], [m|T2], L1, L2, Pin, Pout, N) :- rule(T1, T2, L1, L2, Pin, Pout, 1, i, N, X, X). % rule(InitialString, FinalString, InitStrLength, FinStrLength, % ScanPtrIn, ScanPtrOut, StrPosition, PreviousChar, % RuleNumber, DiffList, DiffLink). % The difference list is used for doing a list concatenate in rule 2. rule([i], [i,u], L1, L2, Pin, Pout, Pos, _, 1, _, _) :- Pos >= Pin, Pout is Pos - 2, L2 is L1 + 1. rule([], L, L1, L2, _, 1, _, _, 2, L, []) :- L2 is L1 + L1. rule([i,i,i|T], [u|T], L1, L2, Pin, Pout, Pos, _, 3, _, _) :- Pos >= Pin, Pout is Pos - 1, L2 is L1 - 2. rule([u,u|T], T, L1, L2, Pin, Pout, Pos, i, 4, _, _) :- Pos >= Pin, Pout is Pos - 2, L2 is L1 - 2. rule([H|T1], [H|T2], L1, L2, Pin, Pout, Pos, _, N, L, [H|X]) :- Pos1 is Pos + 1, rule(T1, T2, L1, L2, Pin, Pout, Pos1, H, N, L, X). print_results([], _). print_results([rule(N,G)|T], M) :- M1 is M + 1, write(M1), write(' '), print_rule(N), write(G), nl, print_results(T, M1). print_rule(0) :- write('axiom '). print_rule(N) :- N =\= 0, write('rule '), write(N), write(' '). lower_bound(N, M, 1) :- N < M. lower_bound(N, N, 2). lower_bound(N, M, B) :- N > M, Diff is N - M, P is Diff/\1, % use and to do even test (P =:= 0 -> B is Diff >> 1; % use shifts to divide by 2 B is ((Diff + 1) >> 1) + 1). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%