Skip to content

Fix SBX prob_bin parameter behavior #673

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

lukepmccombs
Copy link

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:
image

After the fix:
image

@blankjul blankjul self-assigned this Jan 12, 2025
@blankjul
Copy link
Collaborator

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.
Just curious, have you tested your crossover and it performed better?

@lukepmccombs
Copy link
Author

lukepmccombs commented Jan 13, 2025

The issue is that the current implementation introduces new dependencies caused by vectorizing with numpy that I believe were unintentional.

I put together the following experiment to test the performance difference:
https://gist.github.com/lukepmccombs/687158986e0ccfb4e42c65c55f03753b
It measures performance on ZDT6 and the same problem with the parameter landscape alternately flipped for prob_bin = 0.5 and 0.01. The expected behavior should be that the landscape change doesn't effect performance, and that the change in performance due to prob_bin should be roughly the same for either problem.

Running it on main, I get the following results:

ZDT6                   prob_bin: 0.50   95% hv: 0.111553, 0.118944
ZDT6                   prob_bin: 0.01   95% hv: 0.310344, 0.314175    <- Optimal parameters are mostly zeros, so benefited by the bias
AlternatingZDT6        prob_bin: 0.50   95% hv: 0.110402, 0.118404
AlternatingZDT6        prob_bin: 0.01   95% hv: 0.052720, 0.058567    <- Optimal parameters are half zeros, half ones, so hindered by the bias

And on my fork's develop it performs as expected with a not-insignificant performance bump:

ZDT6                   prob_bin: 0.50   95% hv: 0.142128, 0.149016
ZDT6                   prob_bin: 0.01   95% hv: 0.167440, 0.174200
AlternatingZDT6        prob_bin: 0.50   95% hv: 0.140555, 0.147728
AlternatingZDT6        prob_bin: 0.01   95% hv: 0.164799, 0.171331

@lukepmccombs
Copy link
Author

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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants