Genetic Algorithm - Java Crossover - java

With my GA's crossover method, I keep getting an ArrayOutOfBounds Exception while concatenating the mother's second half to the father's first half. The ArrayList's are all the same size. Why does my mother keep trying to access the 10th element in my list of objects? MyPair is an object with a random direction and random number of steps.
We are currently learning this topic in my A.I. class, so I'm not an expert in GA's yet. Any additional commentary on my crossover algorithm is welcomed.
public static class Chromosome{
public ArrayList<MyPair> pairs;
private double x, y;
public double cost;
public Chromosome(){
this.pairs = new ArrayList<MyPair>();
this.x = 100.0; this.y = 100.0;
// not sure if I should do this or not
for(int numPairs = 0; numPairs < 10; numPairs++)
this.addToChromosome();
}
public void addToChromosome(){
MyPair myPair = new MyPair();
this.pairs.add(myPair);
}
public ArrayList<MyPair> getPairsList(){
return this.pairs;
}
public Chromosome crossOver(Chromosome father, Chromosome mother){
Chromosome replacement = new Chromosome();
int pos1 = r.nextInt(father.getPairsList().size());
while(pos1 >= 10)
pos1 = r.nextInt(father.getPairsList().size());
for(int i = 0; i < pos1; i++){
MyPair tempPair = father.getPairsList().get(i);
replacement.getPairsList().set(i, tempPair);
}
for(int i = pos1; i < mother.getPairsList().size() - 1; i++){
MyPair tempPair = mother.getPairsList().get(i);
// ArrayList keeps trying to set out of bounds here
replacement.getPairsList().set(i, tempPair);
}
return replacement;
}

The problem appears to be that you are constructing chromosomes including replacement to have 10 pairs, and then you are setting the element in position i, when i may be 10 or greater.
This has multiple effects you might not have intended. If you splice together a mother and father so that the mother has fewer than 10 pairs, you end up with 10 pairs anyway, with the last ones being just new pairs. If the mother has more than 10 pairs, you are trying to set elements of the arraylist that don't exist, hence you are getting an exception. Another thing you might not have encountered yet is that you haven't copied the information in the pair, you copied the reference to the pair. This means if you give the mother a mutation later by changing the information in the pair rather than replacing a pair, it will affect the child and the child's descendants, which probably is not what you intended.
Instead, start the chromosome with an empty list of pairs, and then add copies of the pairs from the father, and then add copies of pairs from the mother.
Untested code:
public Chromosome crossOver(Chromosome father, Chromosome mother){
Chromosome replacement = new Chromosome();
replacement.getPairsList().clear(); // get rid of the original 10 pairs
int pos1 = r.nextInt(father.getPairsList().size());
while(pos1 >= 10)
pos1 = r.nextInt(father.getPairsList().size());
for(int i = 0; i < pos1; i++){
MyPair tempPair = father.getPairsList().get(i);
replacement.getPairsList().add(tempPair.makeCopy()); // appended copy instead of setting ith
}
for(int i = pos1; i < mother.getPairsList().size() - 1; i++){
MyPair tempPair = mother.getPairsList().get(i);
// ArrayList keeps trying to set out of bounds here
replacement.getPairsList().add(tempPair.makeCopy()); // append copy instead of setting ith
}
return replacement;
}
You have to make a makeCopy method in your Pair class that returns a Pair with the same information. There are other ways to do this.

Related

Issue implementing a recursive shuffle array method in nlog(n) time

I'm trying to implement a recursive shuffle method that will take nlog(n) time but am having major difficulty, given I am restricted to a single parameter and can't include the size of n in my params when calling the recursive method. I looked at the structure of a similar shuffling problem with different parameters and got the idea for how to structure the shuffling using Random, but I've spent way too much time trying to figure out how to implement this.
If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it? How would I go about either decrementing n for the purpose of managing the recursion, or modify a somehow to eventually end the recursion?
*Also, would declaring the objects in the indices like this cause a referential issue? If so, how would I fix this? I tried clone and couldn't get it to function within the requirements of the problem.
public static void shuffle(Object[] a) {
int n = a.length;
if (n == 0) {
return;
}
int d = (int) (Math.random() * (n-1)); //random index
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
shuffle(a);
shuffle(a);
}
***What I've started to implement which looks a lot more like it would work in nlogn time complexity, but not sure if it's right or how it would need to be finished...
public static void shuffle(Object[] a){
if(a.length == 1) return; //return if length = 1: base case
Object[] b = new Object[a.length/2]();
Random rand = new Random(0,a.length); //random index to swap
for(int i = 0; i < b.length; i++){
b[i] = a[rand]; //how do I make sure no index of a is
//repeated?
}
shuffle(b); //recursively call shuffle on b, dividing size by 2
for(int i = 0; i < a.length; i++){
a[i] = b[i]; //copy values from b to a (I guess you could use arraycopy)
}
}
If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it?
It does not have to be a global variable. You can create a class inside your method as follows. This should support any requirement that the implementation must be kept inside the publicly available method. Of course, you'll need to decide if this is in accordance with any other restrictions not mentioned in your question. I leave the actual algorithm up to you. But the array can be shuffled in-place in O(n).
public static void shuffle(Object[] a) {
class Shuffle {
private void recShuffle(Object[] ob, int n) {
// your shuffle algorithm here
}
}
Shuffle s = new Shuffle();
int n = ... // up to you
s.recShuffle(a, n);
}
So I was able to figure out a way to solve it this morning by implementing a helper method and moving most of my code there in case anyone ever comes across a problem like this:
//calls helper shuffle method
public static void shuffle(Object[] a) {
int n = a.length;
helperShuffle(a, n);
}
public static Object[] helperShuffle(Object[] a, int n) {
if (n <= 1)
return a; //base case: size of array is 1
Random rand = new Random(); //declare new random
int d = (rand.nextInt(n)); //random index < n
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
return helperShuffle(a,n-1);
}

A method that returns an array with no duplicates

I am supposed to implement a method in Java that returns an array of integers with no duplicates. I have managed to do it, but my solution seems rather long. I would like to know of ways to improve it.
I added comments so it is easier for your guys to understand what the code does.
public class IntArrayProcessor {
private int[] a;
public IntArrayProcessor(int[] a) {
this.a = a;
}
/**
*
* #return Array with no repeated integers.
*/
public int[] getSet() {
/* creates an array with the same entries and length as this.a */
int[] duplicateA = new int[this.a.length];
/* stores the number of repeated entries in array this.a */
int numberOfDuplicates = 0;
/* is the integer a duplicate or not? */
boolean isDuplicate;
/**
* Counts the number of duplicates in array this.a
*/
for (int i = 0; i < this.a.length; i++) {
duplicateA[i] = this.a[i];
}
for (int i = 0; i < duplicateA.length; i++) {
isDuplicate = false;
for (int j = i + 1; j < this.a.length; j++) {
if (duplicateA[i] == this.a[j]) {
isDuplicate = true;
}
}
if (isDuplicate) {
numberOfDuplicates++;
}
}
/*
* the noDuplicate array has the lenght of the this.a array minus the
* number of repeated entries
*/
int[] noDuplicate = new int[this.a.length - numberOfDuplicates];
/* to keep track of the noDuplicate indexes */
numberOfDuplicates = 0;
/**
* An array with no repeated numbers
*/
for (int i = 0; i < duplicateA.length; i++) {
isDuplicate = false;
for (int j = i + 1; j < this.a.length; j++) {
if (duplicateA[i] == this.a[j]) {
isDuplicate = true;
}
}
if (!(isDuplicate)) {
noDuplicate[numberOfDuplicates] = duplicateA[i];
numberOfDuplicates++;
}
}
return noDuplicate;
}
}
An easy solution is to use the Stream API:
int[] distinctArray = IntStream.of(a).distinct().toArray();
If you don't want to use Stream API you can use a HashSet (or other collections that implement the Set interface).
Set<Integer> set = new HashSet<Integer>(Arrays.asList(array));
That is some rather long code! It seems like you are looking for a more homemade solution than the one that Max put up! Here is some psuedo-code for what I would do:
1. Create a dictionary that takes an int and returns a boolean.
2. For every element in your starting array add it to the dictionary with the boolean value of true (even though the value won't actually matter).
3. Find the number of keys in your dictionary (this will be the number of unique values found in the first array, which is also the length of your new array)
4. Create a new array given the length found in the previous step.
5. Run through each of the keys in the dictionary and add it to the new array!
Shortcut: Instead of step 4 & 5 typically getting the keys from the dictionary will return an array, which would be your end solution.
I'd be happy to write up a more formal solution if that is more helpful.
Note: If you are only familiar with Java, Dictionaries are almost synonymous to HashMaps and can be used interchangeably in this situation. Java's default implementation of a dictionary is called a HashMap
Note 2: Accessing the number of keys/getting all of the keys in a Dictionary/HashMap should be a function built-in, not one you have to write!

Accessing member variables vs creating new object

So I have some code which returns the min and max of an array in an object called min max. My question is inside the for loop do we need to create a new MinMax object at each iteration. Or could we just update MinMax's member variables like so:
globalMinMax.largest = Math.min(globalMinMax.smallest, localMinMax.smallest);
globalMinMax.smallest = Math.max(globalMinMax.largest, localMinMax.largest));
Instead of creating a new MinMax each time like we do on the starred line in the code below
private static class MinMax {
public Integer smallest;
public Integer largest;
public MinMax(Integer smallest, Integer largest) {
this.smallest = smallest;
this.largest = largest;
}
private static MinMax minMax(Integer a, Integer b) {
return Integer.compare(b, a) < 0 ? new MinMax(b, a) : new MinMax(a, b);
}
}
public static MinMax findMinMax(List<Integer> A) {
if (A.size() <= 1) {
return new MinMax(A.get(0), A.get(0));
}
MinMax globalMinMax = MinMax.minMax(A.get(0), A.get(1));
// Process two elements at a time.
for (int i = 2; i + 1 < A.size(); i += 2) {
MinMax localMinMax = MinMax.minMax(A.get(i), A.get(i + 1));
**********Do we need to create a new object here?*****
globalMinMax
= new MinMax(Math.min(globalMinMax.smallest, localMinMax.smallest),
Math.max(globalMinMax.largest, localMinMax.largest));
}
// If there is odd number of elements in the array, we still
// need to compare the last element with the existing answer.
if ((A.size() % 2) != 0) {
globalMinMax
= new MinMax(Math.min(globalMinMax.smallest, A.get(A.size() - 1)),
Math.max(globalMinMax.largest, A.get(A.size() - 1)));
}
return globalMinMax;
}
This code is too complex for what its doing. You should use the MinMax class you've generated to act as a store of the min/max of a list but should not use it during computation.
Finding the minimum/maximum of a list is as simple as:
int minimum = A.get(0);
int maximum = A.get(0);
for(int i=1; i < A.size(); i++){
if(A.get(i) < minimum) minimum = A.get(i);
if(A.get(i) > maximum) maximum = A.get(i);
}
return new MinMax(minimum, maximum);
If you want to incorporate the MinMax class more into the your overall program you can add a static method to the class called something like generateMinMaxFromList that will statically generate minMax objects from supplied Integer lists.
Updating globalMinMax would be the better solution of the two provided if the data is not accessed in a multithreaded environment. You also need not spin up a lot of objects (especially inside a loop) just to find the minimum and maximum value. this can cause overhead when the source collection you're iterating over has a lot of elements.
However, there is one situation in which you'll want to create a new instance of MinMax objects within each iteration. This would be when you spin up multiple threads to act on the data.
Note - the first check within the MinMax method would throw an exception if the list passed in is empty. thus make a check for A.size() == 0 as the first statement within the method and perform the appropriate action.

How to implement a bag-of-words in java

Basically, I need a double-connected Map, which can retrieve value from key and the inverse, I have checked this link, BUT also should be sorted according to the values AND should take multiple values for a single key (I cannot guarantee that there won't be an exact freq for different keys).
So is there any structure with that criteria out there?
Below is the specific problem that imposed this need (maybe I have something missing while I was implementing this but if you know an answer to the above question then you can probably skip it):
I want to implement a bag-of-words method for some features. The idea is to keep only the top k bins with the greatest frequency of occurrence.
To make it more specific let's say I have a codebook
double[10000][d] codebook and a set of features double[][] features. For each line in features, which represent a feature I check the distance from each line in codebook and assign it to the bin having this line a centroid.
Then I increment the index of this bin by 1 until all features have been used.
Then, I would like to keep only the top k bins as results.
The part I am a bit stuck is the one for keeping only the top-k bins. I use a BoundedPriorityQueue<Feature> collection to achieve but I am not sure if there is some simpler approach.
public static BoundedPriorityQueue<Feature> boWquantizerLargerK(double[][] codebook, double[][] features, int featureLength, int maxNumWords) {
HashMap<Integer, Integer> boWMap = new HashMap<Integer, Integer>();
BoundedPriorityQueue<Feature> nn = new BoundedPriorityQueue<Feature>(new Feature(), maxNumWords);
for(int i = 0; i < features.length; i++) {
double[] distCodebook = new double[codebook.length];
for(int j = 0; j < codebook.length; j++) {
double[] dist = new double[featureLength];
for(int k = 0; k < featureLength; k++)
dist[k] = (codebook[j][k] - features[i][k])*(codebook[j][k] - features[i][k]);
distCodebook[j] = MathUtils.sum(dist);
}
Integer index = MathUtils.indexOfMin(distCodebook) + 1;
Integer freq;
if((freq = boWMap.get(index)) == null) {
boWMap.put(index, 1);
nn.offer(new Feature(1, index));
}
else {
boWMap.put(index, ++freq);
nn.offer(new Feature(freq, index));
}
}
return nn;
}
The Feature class is a simple implementation of Comparator:
public class Feature implements Comparator<Feature> {
private Integer freq;
private Integer word;
public Feature() {}
public Feature(Integer freq, Integer word) {
this.freq = freq;
this.word = word;}
public int compare(Feature o1, Feature o2) {
if ((o1).getFrequency() > (o2).getFrequency())
return -1;
else if ((o1).getFrequency() < (o2).getFrequency())
return 1;
else
return 0;}
public double getFrequency() {
return freq;}
}
To summarize the problem, I have a collection which has members pairs of values, the first representing the bin and the second the frequency. This collection is updated until all features have been processed and at which point I just want to keep the bins with the greatest values.
I am using a HashMap<Integer, Integer> structure for the collection and a BoundedPriorityQueue<Feature> for the top k bins.

How to switch int sort to String sort?

I have written some code for sorting random integers that a user inputted. How would I switch this into sorting randomly inputted letters? Aka, user inputs j, s, g, w, and the programs outputs g, j, s, w?
for (int i = 0; i < random.length; i++) { //"random" is array with stored integers
// Assume first value is x
x = i;
for (int j = i + 1; j < random.length; j++) {
//find smallest value in array (random)
if (random[j] < random[x]) {
x = j;
}
}
if (x != i) {
//swap the values if not in correct order
final int temp = random[i];
random[i] = random[x];
random[x] = temp;
}
itsATextArea.append(random[i] + "\n");// Output ascending order
}
Originally I hoped (though I knew the chances of me being right were against me) that replacing all the 'int' with 'String' would work...naturally I was wrong and realized perhaps I had to list out what letter came before which by using lists such as list.add("a"); etc.
I apologize if this seems like I am asking you guys to do all the work (which I'm not) but I'm not entirely sure how to start going about this, so if anyone can give some hints or tips, that would be most appreciated!
You could use String.compareTo() to do that:
Change this:
int[] random = new int[sizeyouhad];
...
if (random[j] < random[x]) {
...
final int temp = random[i];
to:
String[] random = new String[sizeyouhad];
...
if (random[j].compareTo(random[x]) < 0) {
...
final String temp = random[i];
Trial with your code:
String[] random = new String[3];
random[0] = "b";
random[1] = "c";
random[2] = "a";
int x = 0;
//"random" is array with stored integers
for (int i = 0; i < random.length; i++) {
// Assume first value is x
x = i;
for (int j = i + 1; j < random.length; j++) {
//find smallest value in array (random)
if (random[j].compareTo(random[x]) < 0) {
x = j;
}
}
if (x != i) {
//swap the values if not in correct order
final String temp = random[i];
random[i] = random[x];
random[x] = temp;
}
System.out.println(random[i] + "\n");// Output ascending order
}
If you're just trying to sort a list of strings you should probably use the java.util.Collections.sort method rather than writing your own sorting routine.
Was random originally int[]? If you had changed this to String[], you can use String#compareTo method to discern if one string is "less than" another.
Incidentally, you can change the type of random to Comparable[] and then you can use the same algorithm to sort any object whose class implements the interface!
Try to use Collections.sort() function
List<String> l = Arrays.asList("j","s", "g","w");
Collections.sort(l);
If you consider every character to be a code point[1] and you want to sort by Unicode code point order[2], then there is really no need to change your logic. The work is converting from whatever input you are given (String, char[], etc.) into an int[] of the code points.
[1] - http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#codePointAt(int)
[2] - http://en.wikipedia.org/wiki/Code_point
You can make your code work on any type of Object by using generics.
The following code is very simple and works perfectly (With this library you can solve your problem in few lines):
import static ch.lambdaj.Lambda.sort;
import static ch.lambdaj.Lambda.on;
import java.util.Arrays;
import java.util.List;
public class Test{
public static void main(String[] args) {
List<String> list = Arrays.asList("1","102","-50","54","ABS");
List<String> newList = sort(list, on(String.class));
System.out.println(newList);//[-50, 1, 102, 54, ABS]
}
}
This code uses lambda library (download here, website). Find in the website this example:
List<Person> sorted = sort(persons, on(Person.class).getAge());

Categories