GAs: linear rather than generational evolution?...



this message is reused, just seeing if anyone here has anything interesting to say (if there is anyone here to respond...).

note that the current idea for the mutation rate issues is to now use a secondary "meta" vector, which would contain properties related to the evolver's current mutation parameters (itself evolved in pursuit of the best-yeilding parameters...).


note, a more recent/vaguely related idea (aimed at different problems), would use a vaguely similar idea, but treat the vector as a "collection of values", and make use of a secondary piece of information (a "genetic program", which would be using a vaguely postscript-like stack machine model). the "program" in this case would consist of some number of word-coded operation strings (a byte-coded representation is also possible, and is what I had used in the past, but a word-coded representation may be cleaner and more efficient). these strings would be used much like postscript-style blocks or functions, and would be exchanged and mutated during recombination.

thus, this would thus be a combination of several of my past approaches, and could possibly have "some" uses...

or such...


----

well, I am not sure how many people here make use of Genetic Algos...

I guess in my case, I have sometimes.
I guess though in most cases they are too slow to be of much practical use.
my case, I have mostly ended up using them for tuning numerical filters and
similar (such as FIR and IIR filters, used mostly for other tasks such as
signal processing, ...).

ok, in part a lot of this is because I am lazy, and it is easier to wait for
a slower algo to adapt the filters, than try to make sense of and implement
some of the more "correct" algos (root-mean-square and similar beasts...).

in some cases, I use far more simplistic 'voting and weighting' mechanisms
to tune filters, which though generally fast and effective, doesn't really
adapt to the fine details of the data, and has to be adjusted for each
possible use case (the adaptation code for one kind of filter, can't just be
reused unmodified for a different kind of filter).



now, here is something I have done recently:
a variant of a GA was implemented, but I reworked the algo so that it was
linear/iterative, rather than generational.

whether or not it is still a GA, I am not sure, but oh well...


in this case, I am making use of floating point vector arrays (note, I have
implemented other varieties as well, such as string-driven stack machines,
....).

so, here is how it can be used:
app creates a context;
app enters a loop, where:
it fetches a vector from the evolver;
evaluates the vector (doing the test, comming up with an 'error' value);
it sends back the vector and the error value;
continues until a certain number of iterations or a minimum error is
reached.
does whatever with the final result.

this allows a little more freedom than the generational approach, since
allows more immediate feedback, and the tests/usage to be more open ended,
and allows generalizing the API without having to resort to callbacks (it
also simplifies multithreaded usage as well, since one can protect the
evolver with a mutex, and call it from multiple threads).

another possible use is allowing adaptation in more general-purpose
situations (the generational approach is IMO mostly really only usable in
batch-processing style context, wheras an iterative approach may be more
useful in other contexts).

I am less sure of its adaptive properties though, albeit I think they are
both "similar" at least.


the algo itself works about like this:

when fetching a vector:
two vectors are picked from the population (with a strong bias towards
the "good" end);
these vectors are 'bred', and the resultant vector is returned.

when returning a vector:
the oldest vector in the population is discarded;
the new vector is inserted in its respective position.


note that I discard the oldest, not the worst, for the main reason that
there is a risk of "flukes" (generally bad vectors that 'got lucky' on some
of the tests, and they remain lodged near the front of the list by their
unreasonably good success, thus screwing over the process).

by eliminating the oldest vectors, this problem can be reduced (this is less
of a problem with the generational approach, since the whole population is
re-evaluated for each generation, flukes will not remain lodged at the
front). it is assumed that good vectors will be created faster than they
will be destroyed.


another issue is mutation rate:
mutation rate is important, since if it is too low, the algo will take a
super long time to adapt (or get stuck somewhere along the way);
if it is too high, then it is not possible to settle on a good answer, as
the vectors will fly around in the general area, but never really adjust
themselves to the exact values.

with a generational approach, one solution is to steadily vary the mutation
rate, using a high mutation rate in earlier generations and steadily
dropping it as time moves on.

now, without generations this option is no longer available.
the idea was then to add a mini version of the algo, and use it mostly for
adapting the mutation rate (in turn, the algo adapts itself, as it is
adapted by its own output...).


basically, whenever a value comes back, the current mutation rate is also
re-added to its own population, and sorted using the same error as the main
vectors (I guess it would also be possible to use this as sideband data for
the main population, or even as an "extra" component within the vectors).

well, in any case, the basic idea is that the mutation rate will also adapt
in the direction that leads to more accurate results.

note that I have messed with using the error value to directly calculate the
mutation rate, and this allows very fast adaptation, but has to be manually
tuned to get good results...


the current approach also allows that there can be an abrupt change in the
data, and then the mutation rate will rise to a much larger value in order
to compensate.


a current variation will adapt to a 64-point sinewave with an error
threshold of 0.0001 (around 0.0000015625 per element), in about 2.56 million
iterations.

on my computer this takes about 5m 18s for this test.


oddly, with the current settings, it takes about 3.37 million iterations to
tune a 16 point vector to a similar accuracy (it looks like the mutation
rate was having difficulty adjusting low enough, actually, it may make sense
to have a 2-level mutation rate adjuster, rather than a feedbacked
single-level adjuster, which seems overly fussy).

this took about 4m 48s.


I don't know if these are tolerable results or not, oh well...


.