-
Notifications
You must be signed in to change notification settings - Fork 428
Fix SBX prob_bin parameter behavior #673
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
Conversation
The current implementation follows the paper that has been published by Dr. Deb. One issue with the proposed modification could be when their are dependencies across variables. |
I put together the following experiment to test the performance difference: Running it on main, I get the following results:
And on my fork's develop it performs as expected with a not-insignificant performance bump:
|
I've looked through various implementations and papers, and I think the observed behavior was just an unintentional aspect added when parameterizing prob_bin. Firstly, I'll point out that when implementing the sampling for bounded simulated binary crossover, it is more convenient to work with the two parents ordered by the higher and lower value. When randomly ordering any two values, if you assign them equal weight of being the "first" (prob_bin = 0.5 as in all other implementations I found, including early pymoo versions), the resulting distribution is going to be the same no matter the original ordering. Once prob_bin != 0.5, however, the assignment of the weights relative to the ordering starts to matter. My case is that the weights should be assigned by the original ordering of the parents, which this PR enforces. The current implementation for pymoo assigns the weights according to the current ordering at the time of choosing, which is their by-value ordering that was chosen for convenience when sampling. For a single variable, this doesn't matter much since it just reorders the children, but with multiple variables you get the extremal parameter bias I had demonstrated. |
- Preserve parent identity during SBX crossover calculations - Make prob_bin represent probability of parent value exchange - Ensure Child 1 inherits from Parent 1 when prob_bin=0.0 - Use cleaner np.where syntax for child assignment and exchange Addresses #673
- Preserve parent identity during SBX crossover calculations - Make prob_bin represent probability of parent value exchange - Ensure Child 1 inherits from Parent 1 when prob_bin=0.0 - Use cleaner np.where syntax for child assignment and exchange With this fix: - prob_bin=0.0: Child1←Parent1, Child2←Parent2 (no exchange) - prob_bin=0.25: 25% chance of exchange (Child1←Parent2, Child2←Parent1) - prob_bin=0.5: 50% chance of exchange (equivalent to old behavior) - prob_bin=1.0: Always exchange (Child1←Parent2, Child2←Parent1) Addresses #673
Hi @lukepmccombs, I have finally had a chance to think it through and you've identified a real problem with the SBX I've created an alternative solution in PR #725 that addresses the same core issue but with a slightly different approach. Instead of modifying the swapping logic extensively, I preserve parent identity while keeping the SBX calculations intact. My implementation ensures that:
Could you take a look at my approach and let me know what you think? Does this address the same concerns you had with the original implementation? I'm curious to get your feedback on whether this solution would work for your use case. The key difference is that my solution focuses on making Thanks for bringing this issue to attention! |
- Preserve parent identity during SBX crossover calculations - Make prob_bin represent probability of parent value exchange - Ensure Child 1 inherits from Parent 1 when prob_bin=0.0 - Use cleaner np.where syntax for child assignment and exchange With this fix: - prob_bin=0.0: Child1←Parent1, Child2←Parent2 (no exchange) - prob_bin=0.25: 25% chance of exchange (Child1←Parent2, Child2←Parent1) - prob_bin=0.5: 50% chance of exchange (equivalent to old behavior) - prob_bin=1.0: Always exchange (Child1←Parent2, Child2←Parent1) Addresses #673
Resolved with an alternate implementation in #725 |
- Preserve parent identity during SBX crossover calculations - Make prob_bin represent probability of parent value exchange - Ensure Child 1 inherits from Parent 1 when prob_bin=0.0 - Use cleaner np.where syntax for child assignment and exchange With this fix: - prob_bin=0.0: Child1←Parent1, Child2←Parent2 (no exchange) - prob_bin=0.25: 25% chance of exchange (Child1←Parent2, Child2←Parent1) - prob_bin=0.5: 50% chance of exchange (equivalent to old behavior) - prob_bin=1.0: Always exchange (Child1←Parent2, Child2←Parent1) Addresses #673
The prob_bin parameter for SBX behaves incorrectly, where one child is preferentially distributed about the higher values of the parents and the other the lower values. This PR fixes the behavior so prob_bin controls similarity to the parents instead.
Examples for prob_bin=0.25 with 3 variables in [-2, 2]
Parent 1 is [-1, 1, -1]
Parent 2 is [1, -1, 1]
Before the fix:

After the fix:
