-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(GA): replacement
module & BothParent
operator
#263
Conversation
replacement
module & basic operatorsreplacement
module & BothParent
operator
I'm gonna merge this PR right now & respond to any review in followup PR. |
## Description So I've just merged #263 skipping review process 🤦🏻♂️ and had to immediately introduce some fixes; 1. I decided to take ownership of population & children, so that I can modify it in the operator and avoid necessity of creating a copy. 2. Added `requires_children_fitness` method which indicated whether children's fitness should be evaluated. 3. Fixed `BothParents` implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
|
||
/// # Replacement Operator | ||
/// | ||
/// This trait defines common behavirou for crossover operators. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This trait defines common behavirou for crossover operators. | |
/// This trait defines common behaviour for replacement operators. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for the PR itself - LGTM.
As for concerns you mentioned in the description:
- Steady vs non-steady replacement - non-steady version kind of gives us more control over it, i.e. replacement operator is called no matter what implementation of crossover operator (including custom ones) is used. Also, iterating through population another time does increase time complexity, but it does not increase complexity class, so IMO it is acceptable.
- I'm not sure what sort of information such "state" would need, but in case of example given by you - "age" of an individual could be represented by its position in a collection that represents population, i.e. if new ones are only appended at the end, then those at the beginning must be the oldest. Therefore, maybe there is no real need for storing such a state, and this issue could be solved through clever implementation of replacement operators.
This is a valid point, but such approach introduces many difficulties. E.g. many of the replacement operators require knowledge of child's parents (i.e. for given child, we need to know which individuals are its parents) -- right now the only reasonable thing I came up with to realise this is to assume that crossover operator produces children at indices i, i+1 from individuals at i, i+1 positions from original population. But what happens if crossover operator breaks this contract? I've not decided what to do yet :D
I must agree, I believe I'll leave it the way it is right now. But this approach will backfire once the population gets big enough. By "big enough" I mean like couple of hundreds of individuals, as this is a hot code called each iteration it will have serious impact. But I guess we'll have to leave it this way for now as I do not have any other idea for now.
I believe this can not be done the way you described. Right now we assume that the population is of fixed size and the replacement happens in place (also shifting elements in a vector is a bad idea). Also I can not shuffle original population (not children) in any way, because I would lose any parentage information. Such additional state, would allow to associate with given child e.g. a reference to parent individual or number of generations it has lasted up to given point in algorithm's time. W/o that I believe implementing "oldest individual" replacement operator will be impossible. |
Description
First thing to note is that current solution is not really a "steady" replacement.
Currently I've introduced a separate
replacement
operator with the same approach as for other operators: trait + concrete types that implement that trait.What makes it "not steady" is that this operator is passed to GA in the same way as any other operator, and thus it is called separately, after the crossover and there is need to iterate over whole population once again...
To make it "steady" we could pass replacement operator directly to the crossover operator as a parameter / construction parameter - and this is the thing I want your opinion on the most. Should we make the replacement a part of crossover process or should it be a standalone operator?
The second topic is that after
ChromosomeWrapper
was removed in #147 there is no option to define custom state on a individual, thus it makes some variants of replacement operator basically impossible to implement in a reasonable way (such as oldest individual replacement - as you would need to have a lifetime associated with the individual). Therefore I want to open a discussion whether we should bring backChromosomeWrapper
(or some improved version of this concept).If I did not explain things clearly, please ask.
Linked issues
Resolves #58
Important implementation details
Described in previous sections.