This isn't genetic programming at all.<p>What's being described here is a kind of sample-based stochastic optimization which, if I were pressed, is most similar to an algorithm known as a "(mu, lambda) evolution strategy". This is in the general subarea of evolutionary computation. Another algorithm in this area, for example, is the Genetic Algorithm.<p>Genetic Programming (GP) is the application of stochastic optimization techniques to a specific problem: the discovery and optimization of small computer programs or procedures. Because GP is famously associated with candidate solutions in the form of tree structures, it's also applied to non-program optimization as long as the problem involves trees. That's the rough boundary for the community.<p>The most famous example of a genetic programming system in Clojure is Lee Spector's Clojush (<a href="https://github.com/lspector/Clojush" rel="nofollow">https://github.com/lspector/Clojush</a>).
Terminology quibble: My understanding is that "genetic programming" refers not to all evolutionary algorithms, but specifically to those where the code itself (rather than "a few key parameters") is evolved. This doesn't seem to use or implement 'eval' anywhere which I think immediately disqualifies it from meeting that definition.
This brings back memories... One of the greatest heads-down hacking I did was back in the day, running some variant of Common Lisp, working myself through Koza's _Genetic Programming_ book. The designs arrived at were literally non-human. The story of the FPGA tone recognition circuit (spoiler: lot-specific design) was delightful.
The trouble with genetic algorithms is that they are hardly worth it. It's just one of metaheuristics [1], and despite being "biology-inspired" and good-sounding, it does perform worse than simpler alternatives like tabu search [2] or, even better, LAHC [3]. One of the reasons for that is that for local search the speed of neighborhood exploration is paramount, so theoretical advantages of GA get swamped by slower neighborhood iteration. In addition, LAHC or global annealing are <i>way</i> simpler to implement, they are literally just a few lines of code.<p>[1]: <a href="https://en.wikipedia.org/wiki/Metaheuristic" rel="nofollow">https://en.wikipedia.org/wiki/Metaheuristic</a><p>[2]: <a href="https://en.wikipedia.org/wiki/Tabu_search" rel="nofollow">https://en.wikipedia.org/wiki/Tabu_search</a><p>[3]: <a href="https://link.springer.com/chapter/10.1007/978-3-642-41019-2_13" rel="nofollow">https://link.springer.com/chapter/10.1007/978-3-642-41019-2_...</a>
To be fair, the author uses a very simple program: a number that evaluates to itself
to show the general approach for a genetic algorithm.<p>It shows quite nicely the advantages of dynamic typing and abstractions together with very readable data manipulation code.
A great showcase for Clojure's capabilities.<p>Looking forward to the next part where the author wants to mutate s-expressions.<p>(I'm aware that all of this has been done before sometime in the 90s with Prolog and CommonLisp mostly)
I'd also recommend taking a look at the following libraries<p><a href="https://github.com/lspector/Clojush" rel="nofollow">https://github.com/lspector/Clojush</a><p><a href="https://github.com/emilyagras/clojenetics" rel="nofollow">https://github.com/emilyagras/clojenetics</a>
I've always wanted to try genetic algorithms in practice, but whenever I came across a problem that could be solved this way, I was stuck on point 1.<p>How to parametrize my problem? Be it mathematical operations, source code or gates, how to separate it in pieces that can be mutated efficiently?