I want to modify my ArrayList object ( let's call it myObject ) that has similar values with the other objects in the ArrayList.
The problem is that when I modify myObject, it turns out that the other objects with similar values will also get modified.
What might be a possible reason for this problem ? Your answer will help me a lot.
Oh, and I am working on Genetic Algorithm which consists of 3 classes { Genetic_Controller, Chromosome, Fitness_Function } I think this problem occurs at "MutateAtPopulationScale" procedure on Genetic_Controller.
Here is my source code:
Genetic_Controller
package AG;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
public class Genetic_Controller {
public ArrayList<Chromosome> ChromosomeArray; //arraylist containing some Chromosome
private int popSize; // starting number of antibodies
private double pc; // crossover probability
private double pm; // mutation probability
private int maxGen; // maximal reach of generation
private double optimumPrice;
Random r = new Random();
DecimalFormat df = new DecimalFormat("#,###,###,##0");
public Genetic_Controller(int popSize,double pm, int maxGen) {
this.ChromosomeArray = new ArrayList();
this.popSize = popSize;
this.pm = pm;
this.maxGen = maxGen;
}
public double getOptimumPrice() {
return optimumPrice;
}
private double[][] pricesData;
private int genLength;
public void goOptimise(double[][] pricesData, int dataSize) {
this.pricesData = pricesData;
this.genLength = dataSize;
GeneratePopulation();
System.out.println();
for (int g = 0; g < maxGen; g++) {
System.out.println("Generation : " + (g + 1));
ChromosomeSelection();
MutateAtPopulationScale();
ReplacedPopulation();
EvaluateAllChromosome();
System.out.println();
}
}
public void GeneratePopulation() {
Chromosome c;
for (int i = 0; i < popSize; i++) {
c = new Chromosome(genLength);
c.evaluate(pricesData);
ChromosomeArray.add(c);
}
}
public void printPopulation(ArrayList ChromosomeArray) {
int count = 0;
for (Iterator<Chromosome> it = ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
System.out.print((count+1)+". ");
for (int i = 0; i < genLength; i++) {
System.out.print(c.gen.get(i) + " ");
}
System.out.print("__ Price : " + (int) (1000000 / c.getFitness()) + " __ Fitness : " + df.format(c.getFitness()));
System.out.println();
count++;
}
}
public void EvaluateAllChromosome() {
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
c.evaluate(pricesData);
}
}
// Chromosome Selection use Roulette Wheel Selection
public void ChromosomeSelection() {
double totFitness = 0;
double[] RelativeFit = new double[popSize];
double[] CumulativeFit = new double[popSize];
double CumulativeMemory = 0;
ArrayList<Chromosome> NewChromosomeArray = new ArrayList();
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
totFitness = totFitness + c.getFitness();
}
int count = 0;
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
RelativeFit[count] = c.getFitness() / totFitness;
CumulativeFit[count] = CumulativeMemory + RelativeFit[count];
CumulativeMemory = CumulativeFit[count];
count++;
}
double[] rand = new double[popSize];
int temp;
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
for (int j = 0; j < popSize; j++) {
if (CumulativeFit[j] <= rand[i] && CumulativeFit[j + 1] > rand[i]) {
NewChromosomeArray.add(i, ChromosomeArray.get(j + 1));
break;
} else if (rand[i] < CumulativeFit[0]) {
NewChromosomeArray.add(i, ChromosomeArray.get(0));
break;
}
}
}
ChromosomeArray.clear();
ChromosomeArray.addAll(NewChromosomeArray);
}
// Function to add new chromosome to population directly proportional to their fitness values.
public void ReplacedPopulation() {
Collections.sort(ChromosomeArray);
// for (int i = ChromosomeArray.size() - 1; i >= popSize; i--) {
// ChromosomeArray.remove(i);
// }
// System.out.println();
System.out.println("Result Of Replaced Population");
printPopulation(ChromosomeArray);
}
public void MutateAtPopulationScale() {
ArrayList<Integer> mutation_index = new ArrayList();
double[] rand = new double[popSize];
int temp;
System.out.println();
System.out.println("Randomize Result for Mutation");
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
System.out.print(rand[i]+" ");
if (rand[i] < pm) {
mutation_index.add(i);
}
}
System.out.println();
System.out.println("Parent Index that occured mutation");
for (int i = 0; i < mutation_index.size(); i++) {
System.out.println(mutation_index.get(i));
}
int gen1, gen2 = -1;
int gen_temp;
System.out.println("Selected Position of Allels");
for (int i = 0; i < mutation_index.size(); i++) {
// Randomly choose 2 allels position
gen1 = r.nextInt(genLength) + (0);
gen2 = r.nextInt(genLength) + (0);
while (gen2 == gen1) {
gen2 = r.nextInt(genLength) + (0);
}
System.out.println("C"+(i+1)+" : "+gen1+" dan "+gen2);
System.out.println("Index : "+i);
ChromosomeArray.get(mutation_index.get(i)).Mutate(gen1, gen2);
}
System.out.println();
EvaluateAllChromosome();
System.out.println("Mutation Results");
printPopulation(ChromosomeArray);
}
}
Chromosome
package AG;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return gen;
}
public double getFitness() {
return fitness;
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public void Mutate(int genPos1, int genPos2){
int temp;
temp = gen.get(genPos1);
gen.set(genPos1, gen.get(genPos2));
gen.set(genPos2, temp);
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
Fitness_Function
public class Fitness_Function {
public Fitness_Function() {
} //empty constructor
public static double evaluateFunction(ArrayList<Integer> gen, double[][] prices) {
double totalHarga = 0;
double fitness;
for (int j = 0; j < prices.length; j++) {
totalHarga = totalHarga + prices[j][gen.get(j) - 1];
}
fitness = (1 / totalHarga) * 1000000;
return fitness;
}
}
Let me give you a simple example of what actually happened :
chromosome-1 : 1234
chromosome-2 : 3421 (2 and 4 had a similiar values)
chromosome-3 : 1324
chromosome-4 : 3421 (2 and 4 had a similiar values)
chromosome-2 selected for mutation ...
allel no. 1 and 2 selected for mutation ...
mutation result --> Chromosome-2 : 4321
update population ...
chromosome-1 : 1234
chromosome-2 : 4321
chromosome-3 : 1324
chromosome-4 : 4321 (chromosome-4 is also modified)
I think what may be happening is that you are not actually creating new chromosomes and are adding the same chromosome object twice. Objects in java are by reference so creating something like
NewChromosomeArray.add(0, ChromosomeArray.get(0))
NewChromosomeArray.add(1, ChromosomeArray.get(0))
does not create a new object but rather adds the reference from ChromosomeArray index 0 to both places in NewChromosomeArray so a change in the chromosome at NewChromosomeArray index 0 would also appear in the chromosome at NewChromosomeArray index 1 because they are the same chromosome just referenced twice.
One way to be sure that this does not happen again would be to make the chromosome and immutable object like the native string class.
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return new ArrayList<>(gen);
}
public double getFitness() {
return fitness;
}
public Chromosome(ArrayList<String> gen) {
this.gen = new ArrayList<>(gen);
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public Chromosome Mutate(int genPos1, int genPos2){
int temp;
ArrayList<Integer> newGen = new ArrayList<>(gen);
temp = newGen.get(genPos1);
newGen.set(genPos1, gen.get(genPos2));
newGen.set(genPos2, temp);
return new Chromosome(newGen)
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
This way you would create a new chromosome every time you changed the genome.