2

I'm trying to learn about genetic algorithms and am currently working on "crossing over" two "genes". A gene is an integer array, consisting of ones and zeros. To exemplify my problem let's say we have two genes.

int[] geneA = {1,0,0,0,0};
int[] geneB = {0,1,1,1,0};

The expected result from a cross-over, for example at position 3 would be:

geneA = [1,0,0,1,0]
geneB = [0,1,1,0,0]

Meaning that every element at the index of 3 or above would be swapped with the equivalent element of the other gene. To achieve this I wrote the following method:

private void crossOver(int[] geneA, int[] geneB, int pos) {
    int copyA[];
    int copyB[];
    copyA = geneA;
    copyB = geneB;
    for(int i = pos; i < geneA.length; i++) {
        geneA[i] = copyB[i];
        geneB[i] = copyA[i];
    }
    System.out.println(Arrays.toString(geneA);
    System.out.println(Arrays.toString(geneB);
}

However, it seems that the elements of geneB simply get copied into geneA at the index of 3 or higher. The console output is as following:

[1, 0, 0, 1, 0]
[0, 1, 1, 1, 0]

Any explanations or help are highly appreciated. Thanks in advance!

Shinubi
  • 33
  • 4

4 Answers4

4

copyA = geneA does not create a copy. Both variables now refer to the same array.

There is no need to waste time and space on copying the entire array.

When you swap values, you just need to store one of the values in a temporary variable.

private static void crossOver(int[] geneA, int[] geneB, int pos) {
    for (int i = pos; i < geneA.length; i++) {
        int temp = geneA[i];
        geneA[i] = geneB[i];
        geneB[i] = temp;
    }
}

That will update the arrays in-place, so the caller will see the change.

int[] geneA = {1,0,0,0,0};
int[] geneB = {0,1,1,1,0};
crossOver(geneA, geneB, 3);
System.out.println(Arrays.toString(geneA));
System.out.println(Arrays.toString(geneB));

Output

[1, 0, 0, 1, 0]
[0, 1, 1, 0, 0]
Andreas
  • 154,647
  • 11
  • 152
  • 247
2

I think you are going wrong when you create copies of the arrays ... currently you are not making copies but copyA and copyB are just references pointing to geneA and geneB resp

Use Arrays.copy like so,

copyA = Arrays.copyOf(geneA, geneA.length);
copyB = Arrays.copyOf(geneB, geneB.length);
mettleap
  • 1,390
  • 8
  • 17
  • `geneA.clone()` is much simpler than `Arrays.copyOf(geneA,geneA.length)`. The `copyOf` method is needed if you want to change the size, but for a direct copy, `clone` is better. – Andreas Oct 16 '18 at 21:03
  • Yep, you're totally right, I just copied the references. Now everything works as intended. Thanks a lot for your help! – Shinubi Oct 16 '18 at 21:05
1

This code will work:

void crossOver(int[] geneA, int[] geneB, int pos) {
    int copyA[];
    int copyB[];
    copyA = Arrays.copyOf(geneA,geneA.length);
    copyB = Arrays.copyOf(geneB,geneB.length);
    for(int i = pos; i < geneA.length; i++) {
        geneA[i] = copyB[i];
        geneB[i] = copyA[i];
    }
    System.out.println(Arrays.toString(geneA));
    System.out.println(Arrays.toString(geneB));
}

Problem with your code was that you was doing copy of array by:

copyA = geneA;
copyB = geneB;

which just pointed to the same reference. So in the rest of the code you was working on the same array, instead of working on a copy.

Instead proper way of copying arrays is:

copyA = Arrays.copyOf(geneA,geneA.length);
copyB = Arrays.copyOf(geneB,geneB.length);
user987339
  • 10,519
  • 8
  • 40
  • 45
  • `geneA.clone()` is much simpler than `Arrays.copyOf(geneA,geneA.length)`. The `copyOf` method is needed if you want to change the size, but for a direct copy, `clone` is better. – Andreas Oct 16 '18 at 21:02
  • Yep, you're totally right, I just copied the references. Now everything works as intended. Thanks a lot for your help! – Shinubi Oct 16 '18 at 21:04
1

There is problem. you copy both array very easy to copyA and copyB which doesn't make a new copy. it just copy reference of array and both array refer to same memory. so any change in one of them will change other too. for this you can use Arrays.copyof() instead.
I think this is what you want:

    private void crossOver(int[] geneA, int[] geneB, int pos) {
        int[] copyA = Arrays.copyOf(geneA, geneA.length);
        int[] copyB = Arrays.copyOf(geneB, geneB.length);
        for(int i = pos; i < geneA.length; i++) {
            geneA[i] = copyB[i];
            geneB[i] = copyA[i];
        }
        System.out.println(Arrays.toString(geneA));
        System.out.println(Arrays.toString(geneB));
    }

instead of that, as I see, you change geneA and geneB after making copy and swapping, so I think this code will do same with less code but I don't know this is what you want or not:

    private void crossOver(int[] geneA, int[] geneB, int pos) {
        for(int i = pos; i < geneA.length; i++) {
            int temp = geneA[i];
            geneA[i] = geneB[i];
            geneB[i] = temp;
        }
        System.out.println(Arrays.toString(geneA));
        System.out.println(Arrays.toString(geneB));
    }

I hope this help you.

Amin
  • 1,643
  • 16
  • 25
  • `geneA.clone()` is much simpler than `Arrays.copyOf(geneA,geneA.length)`. The `copyOf` method is needed if you want to change the size, but for a direct copy, `clone` is better. – Andreas Oct 16 '18 at 21:03
  • Yep, you're totally right, I just copied the references. Now everything works as intended. Thanks a lot for your help! – Shinubi Oct 16 '18 at 21:05
  • I think. however as I know `System.arraycopy()` must be better. however I don't think there is any difference between them in reality. – Amin Oct 16 '18 at 21:05