Skip to content

Fix/elite set mutation#717

Closed
joszamama wants to merge 11 commits into
mainfrom
fix/elite-set-mutation
Closed

Fix/elite set mutation#717
joszamama wants to merge 11 commits into
mainfrom
fix/elite-set-mutation

Conversation

@joszamama
Copy link
Copy Markdown
Collaborator

DRAFT

@joszamama joszamama marked this pull request as draft October 27, 2025 16:34
@github-actions
Copy link
Copy Markdown

🐰 Bencher Report

Branchfix/elite-set-mutation
Testbedubuntu-latest

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
tests/test_benchmarks.py::test_generate_with_single_hard_constraintLatency
milliseconds (ms)
📈 plot
🚷 threshold
🚨 alert (🔔)
385.20 ms
(+104.58%)Baseline: 188.29 ms
378.52 ms
(101.76%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
tests/test_benchmarks.py::test_generate_with_single_hard_constraint📈 view plot
🚷 view threshold
🚨 view alert (🔔)
385.20 ms
(+104.58%)Baseline: 188.29 ms
378.52 ms
(101.76%)

tests/test_benchmarks.py::test_generate_with_single_soft_constraint📈 view plot
🚷 view threshold
12,235.15 ms
(-32.30%)Baseline: 18,072.33 ms
24,628.55 ms
(49.68%)
tests/test_benchmarks.py::test_init_fandango📈 view plot
🚷 view threshold
151.06 ms
(+1.12%)Baseline: 149.39 ms
155.81 ms
(96.95%)
tests/test_benchmarks.py::test_parse_spec📈 view plot
🚷 view threshold
151.05 ms
(+0.53%)Baseline: 150.25 ms
155.45 ms
(97.17%)
🐰 View full continuous benchmarking report in Bencher

self.crossover_operator = crossover_method
self.mutation_method = mutation_method

# TODO: do this only if initial_population is provided.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at the function, it immediately returns if there is no initial population, so this is probably already ok

self.evaluator.evaluate_population(self.population)
).collect()

# TODO: if no initial population, generate initial population here
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We at some point purposefully started lazy initializing it

:param new_population: The new population to perform crossover on.
:param unique_hashes: The set of unique hashes of the individuals in the new population.
"""
# TODO: crossover should choose from non-elite set only
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it?

:param unique_hashes: The set of unique hashes of the individuals in the new population.
"""
# TODO: crossover should choose from non-elite set only
# TODO: crossover % should mean: if %, cross a single individual, and remove both parents. else, copy random individual from previous gen. remove said individual from selection pool.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to be very careful with this approach with your probabilities, as you don't always remove the same number of individuals from the population. It can work for sure, just keep this in mind so the param setting this probability still behaves intuitively.

"""
# TODO: crossover should choose from non-elite set only
# TODO: crossover % should mean: if %, cross a single individual, and remove both parents. else, copy random individual from previous gen. remove said individual from selection pool.
# TODO: since we produce 1 input per 2 parents, we fill the population until we reach the target size. (NOT DONE HERE, BUT IN generate_simple)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, so we suddenly generate from scratch again? No? Didn't we talk about how this isn't typical?

Comment thread src/fandango/evolution/algorithm.py Outdated

:param new_population: The new population to perform mutation on.
"""
# TODO: remove mutation pool, does not make sense. all population is subject to mutation based on %.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an example of a significant change to the current behavior. We may want to release a new at least minor version after this.

:param new_population: The new population to perform destruction on.
:return: The new population after destruction.
"""
# TODO: find most efficient way to destroy % of population at random.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we remove destruction for now?

:param max_generations: The maximum number of generations to generate. If None, the generation will run indefinitely.
:return: A generator of DerivationTree objects, all of which are valid solutions to the grammar (or satisify the minimum fitness threshold).
"""
# TODO: since initial population was produced during init, we can remove this check.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment

generation = 0

while True:
# TODO: check the stop condition. if fitness is 1.0?
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we stop generating then? Maybe I want more solutions?

self.population_size,
)

# TODO: are we double evaluating here?
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are. All over the place, sometimes nested. Check all the functions when evaluate_individual is passed. Maybe create a wrapper around a tree that contains the eval? This would make it a bit cleaner and would make it easier to reuse previous evals.

@joszamama joszamama closed this May 7, 2026
@riesentoaster riesentoaster deleted the fix/elite-set-mutation branch May 7, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants