jMetal / jMetalPy

A framework for single/multi-objective optimization with metaheuristics
https://jmetal.github.io/jMetalPy/index.html
MIT License
497 stars 150 forks source link

TypeError in PolynomialMutation and SBXCrossover #147

Closed franzscheuer closed 5 months ago

franzscheuer commented 1 year ago

I came across a small bug in the implementation of PolynomialMutation and SBXCrossover.

Both use pow(...) multiple times. Sometimes the exponent is between 0 and 1 by default. Therefore, complex numbers are introduced if the base is negative and a TypeError occurs.

My solution proposal is to add abs(...) around the base of the deltaq computation in PolynomialMutation (line 74 and 78) and around the base of the betaq computation in SBXCrossover (line 173, 175, 182 and 184).

franzscheuer commented 1 year ago

Note: I just noticed the line numbers are off by a few lines in the original post.

ajnebro commented 1 year ago

Hi. I have never found such situations when using polynomial mutation and SBX crossover. What distribution index values are you using?

Antonio

franzscheuer commented 1 year ago

Hi,

for example let's look at the following code-snipet:

betaq = pow(rand*alpha, (1.0/(self.distribution_index + 1.0)))

For any distribution_index -2 > x > 0 there is no problem, since the exponent will not be a fraction value between -1 and 1.

But anything else will result in a value between -1 and 1. And any value to the power of such a value, will be interpreted as root. And the root of a negative number is a complex number.

ajnebro commented 1 year ago

I have used distribution index values within the range (5.0, 400.0).

ajnebro commented 1 year ago

I've applied those operators in many studies in the last 15 years and I have never had an error related to complex numbers in pow(), so this issue is intrigues me.

franzscheuer commented 1 year ago

I see your point. But mathematically it makes sense (in my opinion) to add abs(). I don't always get a negative base, but sometimes.

ajnebro commented 1 year ago

The issue is to decide that, if you get a negative base, that should be considered as an error or as a valid value. If it is the former, using abs() would hide the error, which could be very difficult to find later if an algorithms yields unexpected results.

franzscheuer commented 1 year ago

Sorry for the late answer, I totally get your concern. But since my input variables are not strange at all in my opinion, they somehow still trigger that behavior. I use 9 variables, with lower boundaries [-5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] and upper boundaries [0.0, 50.0, 50.0, 500.0, 1000.0, 2.5, 200.0, 2.5, 50.0]. I don't see how those variables can produce complex numbers.