Skip to content

sbx crossover always returns the lower SBX child, so crossed genes drift towards the lower bound #369

Description

@tachsin

Version: PyGAD 3.7.0 (same code on master)

Found while benchmarking. crossover_type="sbx" always produces the lower of the two SBX children, so every crossed gene lands below its parents' midpoint.

pygad/utils/crossover.py L321-L331:

beta = 1.0 + 2.0 * min(y1 - lower, upper - y2) / (y2 - y1)
alpha = 2.0 - pow(beta, -(eta + 1.0))
rand_u = numpy.random.random()
if rand_u <= 1.0 / alpha:
    beta_q = pow(rand_u * alpha, 1.0 / (eta + 1.0))
else:
    beta_q = pow(1.0 / (2.0 - rand_u * alpha), 1.0 / (eta + 1.0))

child = 0.5 * ((y1 + y2) - beta_q * (y2 - y1))

Here y1 <= y2 and beta_q > 0, so child < (y1 + y2) / 2 every time.

SBX (Deb & Agrawal 1995, "Simulated binary crossover for continuous search space", Complex Systems 9) makes two children, spread symmetrically around the parents' mean:

c1 = 0.5 * [(y1 + y2) - βq (y2 - y1)]
c2 = 0.5 * [(y1 + y2) + βq (y2 - y1)]

and gives each offspring one of them at random (in the bounded version of Deb's NSGA-II code, c1 uses the spread towards the lower bound and c2 the spread towards the upper bound). Always taking c1 moves every crossed gene downwards, so the operator isn't neutral: repeated crossover drifts the population towards the lower bounds. On problems whose optimum is at the lower bound, e.g. ZDT1-3, where the optimal x2..xn are 0, this bias helps; on others it hurts.

Suggested fix: take c1 or c2 with probability 1/2.

-                child = 0.5 * ((y1 + y2) - beta_q * (y2 - y1))
+                if numpy.random.random() < 0.5:
+                    child = 0.5 * ((y1 + y2) - beta_q * (y2 - y1))
+                else:
+                    child = 0.5 * ((y1 + y2) + beta_q * (y2 - y1))
                 child = numpy.clip(child, lower, upper)

(For the exact bounded form, compute a separate beta for c2 from upper - y2, as in Deb's code; the min(...) above already keeps both children within the bounds.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions