Skip to content

Commit

Permalink
adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Hohler committed Apr 16, 2018
1 parent 0d3002a commit c4bb1d8
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 48 deletions.
8 changes: 2 additions & 6 deletions src/genetic/methods/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Population } from "../model/population";

export class Selection {
static RANK = (selectedCandidatesNumber?: number) => <T>(candidates: Candidate<T>[]): Candidate<T>[] => {
const selectedCandidatesSize = selectedCandidatesNumber || Math.floor(candidates.length * 1);
const selectedCandidatesSize = selectedCandidatesNumber || Math.floor(candidates.length * 0.8);
/**
* Sort candidates in ascending fitness order
*/
const sortedCandidates = candidates.sort((a, b) => a.fitness(a.genes) - b.fitness(b.genes));
const selectedCandidates: Candidate<T>[] = [];
const candidatesSize = sortedCandidates.length;
for (let i = 0; i < selectedCandidatesSize - 1; i++) {
for (let i = 0; i < selectedCandidatesSize; i++) {
const pDomain = candidatesSize * (candidatesSize + 1) / 2;
const p = Math.floor(Math.random() * pDomain);
let bornSup = 1;
Expand All @@ -22,10 +22,6 @@ export class Selection {
bornSup += j + 1;
}
}
/**
* The best candidate cheats and always win
*/
selectedCandidates.push(sortedCandidates[candidatesSize - 1]);
return selectedCandidates;
}

Expand Down
2 changes: 1 addition & 1 deletion src/genetic/model/candidate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class Candidate<T extends Gene> {
this.fitness = options.fitness;
this.mutate = options.mutate;
this.crossProbability = options.crossProbability || 0.8;
this.mutationProbability = options.mutationProbability || 0.1;
this.mutationProbability = options.mutationProbability || 0.2;
}

cross = (other: Candidate<T>) => {
Expand Down
13 changes: 11 additions & 2 deletions src/genetic/model/population.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface PopulationOptions<T> {
mutate?: (genes: T[]) => T[];
mutationProbability?: number;
crossProbability?: number;
ellitism?: boolean;
}

export class Population<T extends Gene> {
Expand All @@ -17,6 +18,7 @@ export class Population<T extends Gene> {
mutate: (genes: T[]) => T[];
mutationProbability?: number;
crossProbability?: number;
ellitism: boolean;

/**
* Generate a new randomized population
Expand All @@ -43,6 +45,7 @@ export class Population<T extends Gene> {
this.select = options.select || Selection.RANK();
this.fitness = options.fitness || (() => 0);
this.mutate = options.mutate || (g => g);
this.ellitism = options.ellitism || false;
}

createNextGeneration = (): Population<T> => {
Expand All @@ -55,7 +58,6 @@ export class Population<T extends Gene> {
* Cross stronger candidates and mutates their children
*/
const newCandidates = this.cross(selectedCandidates);

/**
* Add the children to the population
*/
Expand All @@ -66,7 +68,14 @@ export class Population<T extends Gene> {
*/
const cleanedNewGeneration = newGeneration
.sort((a, b) => b.fitness(b.genes) - a.fitness(a.genes))
.slice(0, this.candidates.length);
.slice(0, this.candidates.length - +this.ellitism);

if (this.ellitism) {
// Keep the best oldest candidate
cleanedNewGeneration.push(
this.candidates.sort((a, b) => b.fitness(b.genes) - a.fitness(a.genes))[this.candidates.length - 1]
);
}

return new Population(cleanedNewGeneration, this.getOptions());
}
Expand Down
82 changes: 44 additions & 38 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,62 @@
import { Selection } from "./genetic/methods";
import { Candidate, Population } from "./genetic/model";
import { Network } from "./neural-network/network";

const fitness = (nn: Network) => () => {
// console.log("FITNESS");
// const xorFF = nn.activate([0, 0])[0];
// const errFF = 1 / (1 - xorFF);
// // console.log(xorFF);
const xorFT = nn.activate([0, 1])[0];
// const errFT = 1 / xorFT;
// // console.log(xorFT);
// const xorTF = nn.activate([1, 0])[0];
// const errTF = 1 / xorFT;
// // console.log(xorTF);
// const xorTT = nn.activate([1, 1])[0];
// const errTT = 1 / (1 - xorFF);
// // console.log(xorTT);
// // console.log(1 - xorFF + xorFT + xorTF + 1 - xorTT);
// console.log(errFF, errFT, errTF, errTT);
// return Math.pow(1 / (errFF + errFT + errTF + errTT), 2);
return xorFT;

const PASSWORD = "hardcorepasswordmasterrace";
const fitness = (password: string) => (genes: string[]) => {
const passwordArray = password.split("");
if (genes.length !== password.length) {
throw Error("passwords length not matching");
}
let score = 0;
for (let i = 0; i < genes.length; i++) {
if (genes[i] === passwordArray[i]) {
score += 1;
}
}
return score * 100 / password.length;
};

function mutate(weights: number[]) {
const weightsCopy = weights.slice();
const indexMutated = Math.floor(Math.random() * weightsCopy.length);
weightsCopy[indexMutated] = Math.random() * 2 - 1;
return weightsCopy;
}
const mutate = (password: string) => (genes: string[]) => {
const genesCopy = genes.slice();
const mutatedIndex = Math.floor(Math.random() * PASSWORD.length);
genesCopy[mutatedIndex] = getRandomLetter();
return genesCopy;
};

// Create the networks
const candidates = [];

for (let i = 0; i < 20; i ++) {
const nn = Network.perceptron([2, 4, 3, 1]);
const candidate = new Candidate(nn.weights, {
fitness: fitness(nn),
mutate,
mutationProbability: 1
});
for (let i = 0; i < 100; i ++) {
const genes = generateRandomGenes();
const candidate = new Candidate<string>(
generateRandomGenes(),
{
fitness: fitness(PASSWORD),
mutate: mutate(PASSWORD),
mutationProbability: 0.4
}
);
candidates.push(candidate);
}

const initialPop = new Population(candidates);

let pop = initialPop;

for (let i = 0; i < 3; i ++) {
if (true) {
console.table(pop.candidates.map(it => it.fitness([])));
}
for (let i = 0; i < 100; i ++) {
document.getElementById("main")!.innerHTML
+= ("<br/><br />" + pop.candidates[0].fitness([]));
+= ("<br/><br />" + pop.candidates[0].genes + ", fitness: " + pop.candidates[0].fitness(pop.candidates[0].genes));
pop = pop.createNextGeneration();
}

function generateRandomGenes() {
const genes = [];
for (let i = 0; i < PASSWORD.length; i++) {
genes.push(getRandomLetter());
}
return genes;
}

function getRandomLetter() {
return String.fromCharCode(97 + Math.floor(Math.random() * 26));
}
3 changes: 2 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"arrow-parens": false,
"array-type": [true, "array"],
"variable-name": [true, "check-format", "allow-leading-underscore"],
"max-line-length": [true, 130]
"max-line-length": [true, 130],
"prefer-for-of": false
}
}

0 comments on commit c4bb1d8

Please sign in to comment.