-
I started playing around with prolog recently. Built the hello world of genetic algorithms (onemax). Evolve from a random list of ones and zeros a list of all ones. It works but it is slow. I'm not really looking for ways to super optimize this. I'm hoping for some advice on how to make this fast enough to just play around with more complex evolution tasks without having to go crazy with optimizations. Are there some simple things that I can change to make this usably performant? Anything I did that was dumb from a prolog programming standpoint? I replaced append and flatten with dcgs.
|
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 9 replies
-
Thank you a lot for sharing this! From a quick glance, I noticed a few things:
Regarding performance: It is best to compute the things you need at most once. For example, we can write selection(P0, P1) :- Ws = [_,_], findall(Ws, phrase((...,Ws,...), P0), Ts0), every_other(Ts0, P1). This "pulls" the goal |
Beta Was this translation helpful? Give feedback.
-
Another important thing regarding timing: I think it would be best to model the entire task as a relation between states of interest, so that we get each intermediate step also as a solution on the toplevel instead of only "printing" it manually on the terminal. In this way, we can get timings for each individual step instead of only for the entire sequence. Scryer Prolog makes it easy to see the entire sequence by pressing "a" on the toplevel to see all answers. |
Beta Was this translation helpful? Give feedback.
-
The code after most of the suggested tweeks. Still pondering how to avoid the findall. It is faster. The slowest part is maplist(sum_list, P0, S0). I'm not really sure if there is any way to speed that up. Repurposed the * operator from your book power of prolog and declarative debugging. Super cool.
|
Beta Was this translation helpful? Give feedback.
-
my_sum_list([], 0). my_sum_list([L|Ls], S) :- sum_list_(Ls, L, S). sum_list_([], S, S). sum_list_([L|Ls], S0, S) :- S1 is S0 + L, sum_list_(Ls, S1, S). Even further speedups can be achieved by moving the implementation to Rust, and that may be worth doing for a very small set of very frequently needed predicates (such as |
Beta Was this translation helpful? Give feedback.
-
Big thank you. With the new sum_list it is blazing fast. Thanks for all the other suggestions as well. |
Beta Was this translation helpful? Give feedback.
-
Good news: With the recent For example, try the following query: ?- length(Ls, 1_000_000), maplist(=(1), Ls), sum_list(Ls, S). Ls = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...], S = 1000000. This is very slow in |
Beta Was this translation helpful? Give feedback.
-
On |
Beta Was this translation helpful? Give feedback.
sum_list/2
is currently quite slow: It internally usesfoldl/4
, and that currently doesn't compile away the dynamic call. You can implementsum_list/2
manually much faster:Even further speedups can be achieved by moving the implementation to Rust, and that may be worth doing for a very small set of very frequently needed predicates (such as
length/2
). In general, it is better to instead work on improving the Prolog engine, since that will benefit all programs instead of only these few primitives.