:- module(_,_).
swap_slow(S1, S2) :-
functor(S1, f, 2),
functor(S2, f, 2),
arg(1, S1, X1),
arg(2, S1, Y1),
arg(1, S2, X2),
arg(2, S2, Y2),
X1 = Y2,
X2 = Y1. swap(f(X, Y), f(Y, X)).Try:
?- swap_slow(f(a,b),S).
?- swap(f(a,b),S).
swaps_slow(0).
swaps_slow(N) :-
N > 0,
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
swap_slow(f(a,b), _),
N1 is N - 1,
swaps_slow(N1).
swaps(0).
swaps(N) :-
N > 0,
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
swap(f(a,b), _),
N1 is N - 1,
swaps(N1).
swaps_loop(0).
swaps_loop(N) :-
N > 0,
N1 is N - 1,
swaps_loop(N1).?- speedup_loop(swaps_loop(100000), swaps_slow(100000), swaps(100000)).
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). :- module(_,_).
three_elements_weak(L) :-
length(L, N),
N = 3. three_elements([_,_,_]).Try:
?- three_elements_weak([a,b,c]).
?- three_elements([a,b,c]).
?- three_elements_weak([a,b]).
?- three_elements([a,b]).
test(N) :-
numbers(N, L),
speedup(three_elements_weak(L), three_elements(L)).?- test(10000).
?- test(1000000).
%! \begin{focus}
numbers(0, []).
numbers(N, [N|Ns]) :-
N > 0,
N1 is N - 1,
numbers(N1, Ns).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). Example (real executions):
:- module(_,_).
:- dynamic counting/1.
bad_count(N) :-
assert(counting(N)),
even_worse.
even_worse :-
retract(counting(0)).
even_worse :-
retract(counting(N)),
N > 0,
N1 is N - 1,
assert(counting(N1)),
even_worse. %! \begin{focus}
good_count(0).
good_count(N) :-
N > 0,
N1 is N - 1,
good_count(N1).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)).Try:?- speedup(bad_count(10000), good_count(10000)).
?- speedup(bad_count(100000), good_count(100000)).
good_count(10000) is over 40 times faster than bad_count(10000), and uses virtually no memory.
:- module(_,_).
fib(0, 0).
fib(1, 1).
fib(N, F) :-
N > 1,
N1 is N - 1,
N2 is N1 - 1,
fib(N1, F1),
fib(N2, F2),
F is F1 + F2. :- dynamic lemma_fib/2.
lemma_fib(0, 0).
lemma_fib(1, 1).
lfib(N, F) :-
lemma_fib(N, F),
!.
lfib(N, F) :-
N > 1,
N1 is N - 1,
N2 is N1 - 1,
lfib(N1, F1),
lfib(N2, F2),
F is F1 + F2,
assert(lemma_fib(N, F)). %! \begin{focus}
lfib_fresh(N, F) :-
retractall(lemma_fib(_, _)),
assert(lemma_fib(0, 0)),
assert(lemma_fib(1, 1)),
lfib(N, F).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)).Try:?- speedup(fib(24,_), lfib_fresh(24,_)).The speedup grows with N:
?- speedup(fib(30,_), lfib_fresh(30,_)).If the table is not emptied, lfib/2 just finds the result in it:
?- speedup(fib(24,_), lfib(24,_)).
lfib(24, F) is several hundred times faster than fib(24, F), and uses over 1000 times less memory (and almost no time if called again).
Warning: only useful when intermediate results are reused.
:- module(_,_). :- use_module(library(between)). member_check([X|_],X) :- !. member_check([_|Xs],X) :- member_check(Xs,X).Try (asking for more solutions):
?- member(b,[a,b,c,b]).
?- member_check([a,b,c,b],b).
decomp_simplistic(N, S1, S2) :-
between(0, N, S1),
between(0, N, S2),
N =:= S1 + S2.
decomp(N, S1, S2) :-
between(0, N, S1),
S2 is N - S1.Try (asking for more solutions):?- decomp_simplistic(3,S1,S2).
?- decomp(3,S1,S2).
%! \begin{focus}
all(Goal) :-
call(Goal),
fail.
all(_).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)).?- speedup(all(decomp_simplistic(1000,_,_)), all(decomp(1000,_,_))).
?- speedup(all(decomp_simplistic(3000,_,_)), all(decomp(3000,_,_))).
Naive:
:- module(_,_).
same_elements_naive(L1, L2) :-
\+ (member(X, L1), \+ member(X, L2)),
\+ (member(X, L2), \+ member(X, L1)).Sort and unify (sorting can be done in O(N log N)):same_elements(L1, L2) :-
sort(L1, Sorted),
sort(L2, Sorted).Try:?- same_elements_naive([a,b,c],[c,a,b]).
?- same_elements([a,b,c],[c,a,b]).
test(N) :-
scrambled(N, L),
reverse(L, R),
speedup(same_elements_naive(L,R), same_elements(L,R)).?- test(1000).
?- test(5000).(The numbers 1 to N, scrambled: N must not be a multiple of 7919.)
%! \begin{focus}
scrambled(N, L) :-
scrambled_from(0, N, L).
scrambled_from(N, N, []) :- !.
scrambled_from(I, N, [X|Xs]) :-
X is (I * 7919) mod N + 1,
I1 is I + 1,
scrambled_from(I1, N, Xs).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). generate_z(Z):- generate_x(X), generate_y(X, Y), test_x(X), test_y(Y), combine(X, Y, Z).
generate_z(Z):- generate_x(X), test_x(X), generate_y(X,Y), test_y(Y), combine(X,Y,Z).
generate_z(Z):- generate_x_test(X), generate_y_test(X,Y), combine(X,Y,Z).→ c.f. Constraint Logic Programming!
:- module(_,_). bad_greater(_X,[]). bad_greater(X,[Y|Ys]) :- X > Y, bad_greater(X,Ys).
good_greater([],_X). good_greater([Y|Ys],X) :- X > Y, good_greater(Ys,X).Try:
?- bad_greater(5,[1,2,3]).
?- good_greater([1,2,3],5).
test(N) :-
numbers(N, L),
X is N + 1,
speedup(bad_greater(X,L), good_greater(L,X)).?- test(600000).
%! \begin{focus}
numbers(0, []).
numbers(N, [N|Ns]) :-
N > 0,
N1 is N - 1,
numbers(N1, Ns).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). :- module(_,_).
sum([], 0).
sum([N|Ns], Sum) :-
sum(Ns, Inter),
Sum is Inter + N. sum_iter(L, Res) :-
sum_acc(L, 0, Res).
sum_acc([], Res, Res).
sum_acc([N|Ns], In, Out) :-
Inter is In + N,
sum_acc(Ns, Inter, Out).Try:?- sum([1,2,3],S).
?- sum_iter([1,2,3],S).
test(N) :-
numbers(N, L),
speedup(sum(L,_), sum_iter(L,_)).?- test(100000).
%! \begin{focus}
numbers(0, []).
numbers(N, [N|Ns]) :-
N > 0,
N1 is N - 1,
numbers(N1, Ns).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). <head>:-
<deterministic computation>
<recursive_call>. a:- test_1, !, ... a:- test_2, !, ... ... a:- test_n, !, ...
:- module(_,_).
x2x3([], []).
x2x3([X|Xs], [NX|NXs]) :-
NX is -X * 2,
X < 0,
x2x3(Xs, NXs).
x2x3([X|Xs], [NX|NXs]) :-
NX is X * 3,
X >= 0,
x2x3(Xs, NXs). x2x3_1([], []).
x2x3_1([X|Xs], [NX|NXs]) :-
X < 0,
NX is -X * 2,
x2x3_1(Xs, NXs).
x2x3_1([X|Xs], [NX|NXs]) :-
X >= 0,
NX is X * 3,
x2x3_1(Xs, NXs).Try:?- x2x3([1,-2,3],L).
?- x2x3_1([1,-2,3],L).
test(N) :-
numbers(N, L),
speedup(x2x3(L,_), x2x3_1(L,_)).?- test(100000).
%! \begin{focus}
numbers(0, []).
numbers(N, [N,M|Ns]) :-
N > 0,
M is -N,
N1 is N - 2,
numbers(N1, Ns).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)). With 100,000 elements, delaying the arithmetic is about 1.2 times faster.
:- module(_,_).
x2x3([], []).
x2x3([X|Xs], [NX|NXs]) :-
NX is -X * 2,
X < 0,
x2x3(Xs, NXs).
x2x3([X|Xs], [NX|NXs]) :-
NX is X * 3,
X >= 0,
x2x3(Xs, NXs). x2x3_2([], []).
x2x3_2([X|Xs], Out) :-
X < 0, !,
NX is -X * 2,
Out = [NX|NXs],
x2x3_2(Xs, NXs).
x2x3_2([X|Xs], Out) :-
X >= 0, !,
NX is X * 3,
Out = [NX|NXs],
x2x3_2(Xs, NXs).Try:?- x2x3_2([1,-2,3],L).
test(N) :-
numbers(N, L),
speedup(x2x3(L,_), x2x3_2(L,_)).?- test(100000).
%! \begin{focus}
numbers(0, []).
numbers(N, [N,M|Ns]) :-
N > 0,
M is -N,
N1 is N - 2,
numbers(N1, Ns).
%! \end{focus}
speedup(Slow, Fast) :-
speedup_loop(true, Slow, Fast).
speedup_loop(Loop, Slow, Fast) :-
time_of(Loop, Slow, TS),
time_of(Loop, Fast, TF),
show_speedup(TS, TF).
time_of(Loop, Goal, T) :-
repeat_time(1, Loop, Goal, T).
repeat_time(N, Loop, Goal, T) :-
loop_time(N, Goal, TG),
( TG >= 100
-> loop_time(N, Loop, TL),
( TG - TL > TG / 10 % (else too fast to tell
-> T is (TG - TL) / N % from the loop itself)
; T = 0
)
; N1 is N * 10,
repeat_time(N1, Loop, Goal, T)
).
loop_time(N, Goal, T) :-
statistics(runtime, [T0, _]),
( between(1, N, _), once(Goal), fail ; true ),
statistics(runtime, [T1, _]),
T is T1 - T0.
show_speedup(TS, TF) :-
format("Slow: ", []), show_time(TS),
format(", fast: ", []), show_time(TF),
( TS > 0, TF > 0
-> S is TS / TF,
format(", speedup: ~1f~n", [S])
; nl
).
show_time(T) :-
T > 0, !,
format("~4f ms", [T]).
show_time(_) :-
format("too fast to measure", []).
:- use_module(library(between)).