I am trying to write a java program that generates a population of random characters and eventually lands at an inputted string to simulate something like the infinite monkey theorem (https://en.wikipedia.org/wiki/Infinite_monkey_theorem). The issue I am having is as I am testing it, all of the starting population have a fitness level of 0 so nothing gets added to the mating pool during the natural selection process. Here is what the project entails.
Target: the string "Hello"
Mutation Rate: 0.01
Population Max: 100 DNA objects each containing a char[] array for the genes.
Here is my function for calculating the fitness:
public void calcFitness(String target){
double score = 0.0;
for(int i = 0; i < this.genes.length; i++){
if(this.genes[i] == target.charAt(i)){
score++;
}
}
this.fitness = score/this.genes.length;
}
I am new to genetic programming and not sure what I am doing wrong, any help would be appreciated and any tips or insight about genetic programming would also be appreciated.
EDIT
Here is the code for the selection process:
public void naturalSelection(){
ArrayList<DNA> selection = new ArrayList<>();
Random rand = new Random();
String child = "";
DNA[] newPop = new DNA[popMax];
for(int i = 0; i < population.length; i++){
for(int j = 0; j < population[i].getFitness(); j++){
selection.add(population[i]);
}
}
for(int i = 0; i < selection.size(); i++){
int parentSelect = rand.nextInt(selection.size());
DNA parent1 = selection.get(parentSelect);
child = parent1.split(true);
parentSelect = rand.nextInt(selection.size());
DNA parent2 = selection.get(parentSelect);
child += parent2.split(false);
newPop[i] = new DNA(child);
}
double mutation = rand.nextDouble();
if(mutation < this.mutationRate){
this.population = swapMutation(newPop);
calcFittest();
}
else{
this.population = newPop;
calcFittest();
}
}
Where swap mutation swaps two random chars if mutation occurs.
I would suggest using a fitness function that measures distance from a candidate to the target string. You would then minimise overall fitness instead of maximising.
To do this:
public void calcFitness(String target){
double score = 0.0;
for(int i = 0; i < this.genes.length; i++){
score += Math.abs((int)this.genes[i] - (int)target.charAt(i));
}
this.fitness = score / this.genes.length;
}
This should work better because it will differentiate each candidate much better. Without seeing the random string generator you are using it is hard to say but it is likely that the number of possible candidates is astronomical with a very low chance that any of them score a single point with your fitness function.
Might also be worth pointing out that your code is likely part of a Genetic Algorithm rather than Genetic Programming.
If you want to improve the selection I would recommend as an easy to program technique Tournament Selection - choose n random individuals from the population and then select the best fitness individual from the n individuals. This gives better candidates a higher chance of being selected than other individuals and has the added bonus that you don't need to calculate fitness for every individual in a population.
I just finished a GA for infinite monkey theorem. You may find at https://github.com/Willtl/infinite_monkey_theorem
It is in C++ but it would not be difficult to do the same in Java. You can open the project it using Eclipse CPP.
void Individual::calculateFitness(vector<char> chromosomePlate) {
fitness = 0;
for (int i = 0; i < chromosome.size(); i++) {
int gene = (int) chromosome[i];
int genePlate = (int) chromosomePlate[i];
if (gene == genePlate && gene != 32) {
fitness++;
}
}
First of all, when I read the input I put it to lower case. Then to make it easy to randomize and compare, I am using ASCII. So as I am just considering lower case my characters range goes from 97 to 122. I also keep the spaces at the chromosome, however in the fitness function I ignore it (32).
Anything that you need just post here I will be more than happy to help.
Related
I'm having a lab about making a Merkle Hellman Knapsack,the request said i need to make an automatically super increasing array but i don't know how to make it,is there any way to make it ? Thanks for reading
Random random = new Random();
int[] wInt = random.ints(8, 1, 999).toArray();
for(int i = 0; i < 8 - 1; i++) {
for (int j = i + 1; j < wInt.length; j++) {
if(wInt[i] > wInt[j]) {
int temp = wInt[i];
wInt[i] = wInt[j];
wInt[j] = temp;
}
}
}
A superincreasing sequence is one where each term is at least as big as the sum of all the preceding terms. Therefore, one way to generate a superincreasing sequence would be to keep track of the sum of all elements currently in the sequence, then to add some random, nonzero number onto the total when forming the next element. In pseudocode:
sequence = []
total = 0
while the sequence has fewer than n items in it:
total += some random number
append total to the sequence
I'll leave it as an exercise to translate this into your Programming Language of Choice.
Problem:
You need to pack several items into your shopping bag without squashing anything. The items are to be placed one on top of the other. Each item has a weight and a strength, defined as the maximum weight that can be placed above that item without it being squashed. A packing order is safe if no item in the bag is squashed, that is, if, for each item, that item’s strength is at least the combined weight of what’s placed above that item. For example, here are three items and a packing order:
This packing is not safe. The bread is squashed because the weight above it, 5, is greater than its strength, 4. Swapping the apples and the bread, however, gives a safe packing.
Goal:
I need to find all the solutions to this problem with choco solver then test if this solution is enumerated:
N=3, WS = { (5,6), (4,4), (10,10) }
What I tried:
First I wrote my CSP model
Then I wrote my choco code like that
public static void main(String[] args) {
int[][] InitialList = {{5,6}, {4,4}, {10,10}};
int N = InitialList.length;
Model model = new Model("SafePacking");
// Create IntVars of weights and strengths
IntVar[] weights = new IntVar[N], strengths = new IntVar[N];
for (int i = 0; i < N; i++) {
weights[i] = model.intVar("Weight"+i, InitialList[i][0]);
strengths[i] = model.intVar("Strength"+i, InitialList[i][1]);
}
// Create IntVar of positions
IntVar[] positions = model.intVarArray("P",N, 0, N-1);
model.allDifferent(positions).post();
for(int i = 0; i < N; i++) {
int sum = 0;
for(int j = 0; j < N; j++)
if (positions[j].getValue() < positions[i].getValue())
sum += weights[j].getValue();
model.arithm(model.intVar(sum), "<=", strengths[i]).post();
}
Solution solution = model.getSolver().findSolution();
System.out.println(solution);
}
But I've got this result :
Solution: P[0]=0, P[1]=1, P[2]=2
Which is a wrong solution.
Did I miss something ?
The computation of sum seems to assume that the variables have a defined value, which they do not have. Calling getValue() on an uninstantiated IntVar will give the lower bound for a variable in Choco.
To make your model work, you need to build up sum as an IntVar instead.
I'm making a Sudoku program, and I wanted to store every combination of x bits in an 81-bit integer into a list. I want to be able to then shuffle this list, iterate through it, and each on-bit will represent a cell that is to be removed from an existing Sudoku grid, x depending on difficulty. My program then tests this unique puzzle to see if it's solvable, if not, continue to the next combination. Do you guys understand? Is there a better way?
Currently I have a for-loop with a BigInteger, adding 1 every iteration, and testing to see if the resulting number has a number of bits on equal to 55. But this takes LOOOOOONG time. I don't think there's enough time in the universe to do it this way.
LOOP: for(BigInteger big = new BigInteger("36028797018963967");
big.compareTo(new BigInteger("2417851639229258349412351")) < 0;
big = big.add(big.ONE))
{
int count = 0;
for(int i = 0; i < 81; i++)
{
if(big.testBit(i)) count++;
if(count > 55) continue LOOP;
}
//just printing first, no arraylist yet
if(count == 55) System.out.println(big.toString(2));
}
As you already noticed, storing all combinations in a list and then shuffling them is not a viable option.
Instead, you can obtain a shuffled stream of all combinations, by using the Streamplify library.
import org.beryx.streamplify.combination.Combinations;
...
SudokuGrid grid = new SudokuGrid();
int[] solvedPuzzle = IntStream.range(0, 81).map(i -> grid.get(i)).toArray();
int k = 55;
new Combinations(81, k)
.shuffle()
.parallelStream()
.map(removals -> {
int[] puzzle = new int[81];
System.arraycopy(solvedPuzzle, 0, puzzle, 0, 81);
for(int i : removals) {
puzzle[i] = 0;
}
return puzzle;
})
.filter(puzzle -> resolveGrid(new SudokuSolver(new Candidates(puzzle))))
//.limit(10)
.forEach(puzzle -> System.out.println(Arrays.toString(puzzle)));
You probably don't want to generate all puzzles of a given difficulty, but only a few of them.
You can achieve this by putting a limit (see the commented line in the above code).
Certainly there are methods that will finish before you die of old age. For example:
Make an array (or BitSet, as David Choweller suggested in the comments) to represent the bits, and turn on as many as you need until you have enough. Then convert that back into a BigInteger.
I appreciate any feedback. The following seems to be a better option than my initial idea, since I believe having a list of all possible combinations would definitely give an out of memory error. It's not perfect, but this option takes out a random cell, tests to see if its solvable, if not put the last taken number back, and continue to remove the next random cell until enough cells have been taken out, or start over.
int[] candidates = new int[81];
SudokuGrid grid = new SudokuGrid();
LOOP: while(true)
{
ArrayList<Integer> removals = new ArrayList<Integer>();
for(int i = 0; i < 81; i++)
{
removals.add(i);
candidates[i] = grid.get(i);
}
Collections.shuffle(removals);
int k = 55;
for(int i = 0; i < k; i++)
{
int num = candidates[removals.get(i)];
candidates[removals.get(i)] = 0;
cand = new Candidates(candidates);
SudokuSolver solver = new SudokuSolver(cand);
if(!resolveGrid(solver))
{
candidates[removals.get(i)] = num;
k++;
if(k > removals.size())
continue LOOP;
}
}
break;
}
This takes about 5 seconds to solve. It's a bit slower than I wanted it to be, but a lot of it depends on the way I coded the solving strategies.
Birthday probability problem
here is the algorithm which i follow, bit i still face problem. The algorithm is
To simplify the problem, we make the assumption that each day of the year (except February 29) is equally likely for a birthday. We will only consider 365 days in a year.
When generating a random birthday for a person, generate a random integer in the range 0-364, each number will represent an individual day in a year (0 for January 1st, and 364 for December 31st). We will use zero-based numbers to match array indexing.
When performing a single simulation, remember you only need to find one pair of matching birthdays to make the simulation count. That is, as soon as you determine that two people have the same birthday you can stop the current simulation and start the next simulation.
To ensure that everyone’s program behaves the same (so that we can auto-grade everyone’s submission), you will need to create a new Random object for each simulation run, and you will need to seed the Random object with the number of the run you are simulating (the first simulation run will use the integer 1 as the seed, the second run will use 2, etc.). You need to create a new Random object per simulation run, not per random number needed [do not use the Math.random() method in this program].
During one simulation, you will need to keep track of the days which ``correspond to someone’s birthday, or alternatively keep track of the number of birthdays that occur on any given day. There are several structures that we studied in this module of the MOOC that could be used to easily solve this problem. You are free to pick the structure of your choice. Note that the goal is to simply determine if two birthdays land on the same date.
When returning the final result, return the percentage in the range 0.0 – 100.0.
enter code here
import java.util.HashSet;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
public class Logic {
public static void process(int size, int count)
{
int number = 0;
Set<Integer> bdays = new HashSet<>();
int x[] = new int[size];
Random random = new Random();
random.setSeed(1);
int matches = 0;
boolean out = false;
for (int i = 0; i < count; i++) {
for (int j = 0; j < size; j++) {
number=(random.nextInt(365)+1);
}
for (int j = 0; j < count; j++) {
if (bdays.contains(number)) {
matches++;
}
else
{ bdays.add(number);
out = true;
break;}
if (out) {
out = false;
break;
}
}
}
double prob = 100*(double) matches / count;
System.out.println("The probability for two students to share a birthday is " + prob + ".");
}
public static void main(String[] args) {
Scanner inp = new Scanner(System. in );
System.out.println("How many students?");
int num = inp.nextInt();
System.out.println("How many times?");
int times = inp.nextInt();
process(num,times);
}
}
I suspect there are a few things wrong, but here's the first one: You're always adding number to bdays as soon as you assign number. You then later check to see if number is in bdays, which of course it will be - thus why you get the 100% match rate. What you need to do is:
Pick number
Check if number is already in bdays, and increment the counter if it is
Add number to bdays
I have the following code to set 10 random values to true in a boolean[][]:
bommaker = new boolean[10][10];
int a = 0;
int b = 0;
for (int i=0; i<=9; i++) {
a = randomizer.nextInt(9);
b = randomizer.nextInt(9);
bommaker[a][b] = true;
}
However, with this code, it is possible to have the same value generated, and therefore have less then 10 values set to random. I need to build in a checker, if the value isn't already taken. And if it is already taken, then it needs to redo the randomizing. But I have no idea how to do that. Can someone help me?
simplest solution, not the best:
for (int i=0; i<=9; i++) {
do {
a = randomizer.nextInt(10);
b = randomizer.nextInt(10);
} while (bommaker[a][b]);
bommaker[a][b] = true;
}
You're problem is similar to drawing cards at random from a deck if I'm not mistaken...
But first... The following:
randomizer.nextInt(9)
will not do what you want because it shall return an integer between [0..8] included (instead of [0..9]).
Here's Jeff's take on the subject of shuffling:
http://www.codinghorror.com/blog/2007/12/shuffling.html
To pick x spot at random, you could shuffle your 100 spot and keep the first 10 spots.
Now of course seen that you'll have only 10% of all the spots taken, simply retrying if a spot is already taken is going to work too in reasonable time.
But if you were to pick, say, 50 spots out of 100, then shuffling a list from [0..99] and keeping the 50 first value would be best.
For example here's how you could code it in Java (now if speed is an issue you'd use an array of primitives and a shuffle on the primitives array):
List<Integer> l = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
l.add(i);
}
Collections.shuffle(l);
for (int i = 0; i < n; i++) {
a[l.get(i)/10][l.get(i)%10] = true;
}