Why does my Multilayer Perceptron only classify linearly?
Your error calculation looks wrong:

if output1 &lt; 0.99:
    error += (output1)**2
if output2 &gt; 0.01:
    error += (1-output2)**2


If I am reading this correctly, output1 = 1.0 is a correct classification, since you treat any value above 0.99 as no error at all. However, you then measure the squared error as being output1 ** 2 which means the largest error is at 0.99. This is going to confuse the network, it will treat classifications above the line as perfect 1.0 if they score > 0.99, or otherwise want to adjust weights to make the classification 0.0. The opposite is true for your scoring of points under the line. 

You need to either


Swap the conditionals (change &lt; 0.99 to &gt; 0.01 and vice-versa)


or


Replace (output1) with (1-output1) and (1-output2) with (output2) 


in order to make the logic self-consistent. Which you choose depends on whether above the line points are positive class, or it is the negative ones. If above the line is positive you should use option 2.

In addition, as comments have pointed out, you might be a little ambitious with your approach. I spot the following things that make your job harder:


Using genetic algorithm search. Whilst it is possible to train small NNs like yours using a GA, it is less efficient. GAs might be a good choice for control systems or for a-life scenarios, but are far behind cutting edge for supervised learning.
Using mean squared error metric for classification. You should use logloss, which more heavily penalises bad guesses. With a mean squared error, there is a higher chance the network will settle for a few bad misclassifications if it also gets some other reasonable ones.
Ambitious function to separate. A neural network should be able to classify your function, but that's a lot of curvature to learn for a starting problem. Reduce it to just a couple of cycles to start with should help you debug practical issues.
No input normalisation. This may lead to saturated values in the network - close to 1.0 or 0.0, making it very hard to discriminate between good and bad weights. You don't show your weight initialisations - large initial weights can also cause this effect (although using a GA may actually help here, depending on how you are mutating weights).