refactor(lib): Allow fitting whole population at once
The fitness function gets fit_population function. The default
implementation is going over fit() one by one, but it can be
reimplemented by specific types.
feat(lib): constraints along with evolutionary strategies
feat(lib): allow modifying fitness function in evolution_algorithm
chore: move population structs to separate module
feat: split params out of PerturbationOperator to allow for non-'static PerturbationOperator
This means PerturbationOperators can now hold non-'static references.
Right away, utilize this in the Random2OptPerturbation for the TSPInstance.
feat: add a lot of algorithm showcases
feat(lib): add evaluation count to EA stats
fix(lib): do not take mut self in population.iter()
feat(lib): add roulette wheel selection
feat(lib): add random search
feat(lib): add n consecutive bit flip perturbation for binary string
feat(lib): add two point and n point crossovers
refactor(lib): implement generic evolutionary strategy using .wrapped_mut
Thanks to wrapped_mut now the one_to_five strategy can be implemented
without relying on BoundedPerturbation etc.
feat: add possibility to evolve strategy during evolution_algorithm
refactor: generalize apply_to_mutations
refactor(lib): allow modifying mutation perturbation
refactor(lib): add methods to get wrapped perturbations instead of traits.
Remove WrapperPerturbation and ListWrapperPerturbation in favor of
wrapped and wrapped_mut functions on PerturbationOperator. This
allows for easier handling as it's not easy to downcast Any into
WrapperPerturbation or ListWrapperPerturbation. So instead
always return dyn PerturbationOperator instead of dyn Any.
Use dyn Any only for downstasting to concrete types.
This finally allows for apply_to_mutations to be implemented
under MutationPerturbation, allowing to modify the arguments.
chore: do not clone for no reason in local search
feat: add into_iter for population