1:- use_module(library(lists)). 2 3 4shrink(any, X, X). 5 6shrink(atom, Atom, Shrunk) :- 7 atom_codes(Atom, Codes0), 8 shrink(codes, Codes0, Codes), 9 atom_codes(Shrunk, Codes). 10 11shrink(code, _, 0'a). 12shrink(code, _, 0'b). 13shrink(code, _, 0'c). 14shrink(code, _, 0' ). 15 16shrink(codes, Codes0, Codes) :- 17 shrink(list(code), Codes0, Codes). 18 19shrink(integer, _, 0). % zero often triggers bugs 20shrink(integer, X, Y) :- 21 % bisect from 1 towards the integer 22 X > 0, 23 MaxExponent is floor(log(abs(X))), 24 between(0,MaxExponent,Exponent), 25 Y is sign(X) * round(exp(Exponent)). 26shrink(integer, X, Y) :- 27 % try a positive version of a negative integer 28 X < 0, 29 Y is -X. 30 31shrink(list, L0, L) :- 32 shrink(list(any), L0, L). 33 34shrink(list(_), L0, L) :- 35 shrink_list_bisect(L0, L). 36shrink(list(Type), L0, L) :- 37 shrink_list_one(Type, L0, L). 38 39shrink(string, String, Shrunk) :- 40 string_codes(String, Codes), 41 subset_gen(ShrunkCodes, Codes), 42 string_codes(Shrunk, ShrunkCodes). 43 44 45% help shrink lists with bisection 46shrink_list_bisect(L0, L) :- 47 length(L0, Len), 48 Len > 0, 49 MaxExponent is ceiling(log(Len)), 50 between(0,MaxExponent,Exponent), 51 N is round(exp(MaxExponent-Exponent)), 52 shrink_list_bisect_(L0, Len, N, L). 53 54% shrink by removing large pieces of a list 55shrink_list_bisect_([], _, _, []). 56shrink_list_bisect_(_, Len, N, []) :- 57 N > Len. 58shrink_list_bisect_(L0, Len, N, L) :- 59 length(Front, N), 60 append(Front, Back, L0), 61 ( L = Back 62 ; BackLen is Len - N, 63 shrink_list_bisect_(Back, BackLen, N, NewBack), 64 append(Front, NewBack, L) 65 ). 66 67% shrink by removing or shrinking individual list elements 68shrink_list_one(_, [], []). 69shrink_list_one(Type, [H0|T], [H|T]) :- 70 shrink(Type, H0, H). 71shrink_list_one(Type, [H|T0], [H|T]) :- 72 shrink_list_one(Type, T0, T).
base case
80subset_gen([], []). 81% inductive case 82subset_gen(Subset, [_ | Set]) :- subset_gen(Subset, Set). 83subset_gen([H |Subset], [H | Set]) :- subset_gen(Subset, Set)