Как изменить значение объекта в ArrayList, значение которого аналогично другим объектам - PullRequest
0 голосов
/ 24 сентября 2018

Я хочу изменить мой объект ArrayList (назовем его myObject), который имеет значения, аналогичные другим объектам в ArrayList.

Проблема в том, что когда я изменяю myObject, оказывается, что другие объекты с аналогичными значениями также будут изменены.

Что может быть причиной этой проблемы?Ваш ответ мне очень поможет.

О, и я работаю над Генетическим алгоритмом, который состоит из 3 классов {Genetic_Controller, Chromosome, Fitness_Function} Я думаю, что эта проблема возникает в процедуре "MutateAtPopulationScale" на Genetic_Controller.

Вот мой исходный код:

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);
                    }
            }

Хромосома

 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;

    }

}

Позвольте мне привести простой пример того, что на самом деле произошло:

хромосома-1: 1234
хромосома-2: 3421 (2 и 4 имелианалогичные значения)
хромосома-3: 1324
хромосома-4: 3421 (2 и 4 имели сходные значения)

хромосома-2, выбранная для мутации ...
аллель №1 и 2 выбраны для мутации ...
результат мутации -> Хромосома-2: 4321

обновить популяцию ...
хромосома-1: 1234
хромосома-2: 4321
хромосома-3: 1324
хромосома-4: 4321 (хромосома-4 также модифицирована)

1 Ответ

0 голосов
/ 02 октября 2018

Я думаю, что может случиться так, что вы на самом деле не создаете новые хромосомы и дважды добавляете один и тот же объект хромосомы.Объекты в java являются ссылками, поэтому создание чего-то вроде

NewChromosomeArray.add(0, ChromosomeArray.get(0))
NewChromosomeArray.add(1, ChromosomeArray.get(0))

не создает новый объект, а скорее добавляет ссылку из индекса ChromosomeArray в оба места в NewChromosomeArray, так что изменение хромосомы в индексе NewChromosomeArray 0 будеттакже появляются в хромосоме по индексу 1 NewChromosomeArray, потому что они являются одной и той же хромосомой, на которую ссылаются дважды.

Один из способов убедиться, что это больше не повторится, состоит в том, чтобы сделать хромосому и неизменяемый объект, как собственный класс строки.

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;
}

}

Таким образом, вы будете создавать новую хромосому каждый раз, когда меняете геном.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...