-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
936 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
class AI { | ||
constructor (NeuralNetwork, populationSize, mutation, variationMutation, maxGenerations) { | ||
this.maxGenerations = maxGenerations; | ||
this.NeuralNetwork = NeuralNetwork; | ||
this.populationSize = populationSize; | ||
this.population = Array(); | ||
this.mutation = mutation; | ||
this.variationMutation = variationMutation; | ||
this.generation = 0; | ||
this.actualSubject = 0; | ||
this.learning = false; | ||
this.numberOfChromosomes = 2; | ||
this.parentSurvive = true; | ||
|
||
this.init(); | ||
} | ||
|
||
startLearning() { | ||
this.learning = true; | ||
} | ||
|
||
stopLearning() { | ||
this.learning = false; | ||
} | ||
|
||
init() { | ||
this.resetGeneration(); | ||
this.createNewPopulation(); | ||
} | ||
|
||
setInput (input) { | ||
this.NeuralNetwork.setInput(input); | ||
} | ||
|
||
calculate () { | ||
return this.NeuralNetwork.calculate(); | ||
} | ||
|
||
resetGeneration () { | ||
this.actualSubject = 0; | ||
this.generation++; | ||
} | ||
|
||
createNewPopulation (startPopulation) { | ||
if (!startPopulation) | ||
var newPopulation = Array(); | ||
else | ||
var newPopulation = startPopulation; | ||
|
||
for (let i=newPopulation.length; i<this.populationSize; i++) { | ||
newPopulation.push(new Chromosome(this.NeuralNetwork.inputSize, this.NeuralNetwork.hiddenSize)); | ||
} | ||
this.population = newPopulation; | ||
|
||
this.NeuralNetwork.setHiddenLayer(this.population[this.actualSubject]); | ||
|
||
document.dispatchEvent(new CustomEvent('onNewPopulation', {detail : {population:this.population}})); | ||
} | ||
|
||
evolve () { | ||
if (this.learning && this.generation < this.maxGenerations) { | ||
var bestGens = this.selectBestPopulation(); | ||
var newGeneration = Array(); | ||
var crossover = this.copyChromosome(this.doCrossover(bestGens)); | ||
if (this.parentSurvive) { | ||
this.resetFitness(bestGens); | ||
newGeneration = bestGens; | ||
} | ||
newGeneration = newGeneration.concat(crossover); | ||
|
||
this.resetGeneration(); | ||
|
||
this.createNewPopulation(this.mutate(newGeneration)); | ||
} | ||
} | ||
|
||
nextSubject () { | ||
if (this.generation >= this.maxGenerations) this.stopLearning(); | ||
if (!this.learning) return; | ||
|
||
if (this.actualSubject == this.population.length-1) { | ||
this.evolve(); | ||
} else { | ||
this.actualSubject++; | ||
this.NeuralNetwork.setHiddenLayer(this.population[this.actualSubject]); | ||
} | ||
} | ||
|
||
mutate (chromosomes) { | ||
for (let i=0; i<chromosomes.length; i++) { | ||
chromosomes[i].mutate(this.mutation, this.variationMutation); | ||
} | ||
return chromosomes; | ||
} | ||
|
||
addFitness () { | ||
if (!this.learning) return; | ||
|
||
this.NeuralNetwork.addFitness(); | ||
} | ||
|
||
resetFitness (chromosomes) { | ||
for (let i=0; i<chromosomes.length; i++) { | ||
chromosomes[i].resetFitness(); | ||
} | ||
} | ||
|
||
doCrossover (chromosomes) { | ||
|
||
if (chromosomes.length > 2) { | ||
console.log("Número máximo de Chromosomes para Crossover é 2"); | ||
return false; | ||
} | ||
var sliceSize1 = Math.floor(Math.random()*(this.NeuralNetwork.hiddenSize - 1 + 1) + 1); | ||
var sliceSize2 = sliceSize1 - this.NeuralNetwork.hiddenSize; | ||
|
||
var n1 = chromosomes[0].neurons; | ||
var n2 = chromosomes[1].neurons; | ||
|
||
var slice1 = n1.slice(0, sliceSize1-1); | ||
var slice2 = n1.slice(sliceSize1-1); | ||
var slice3 = n2.slice(0, sliceSize2-1); | ||
var slice4 = n2.slice(sliceSize2-1); | ||
|
||
var c1 = slice1.concat(slice4); | ||
var c2 = slice3.concat(slice2); | ||
|
||
var chromosome1 = new Chromosome(this.NeuralNetwork.inputSize, this.NeuralNetwork.hiddenSize); | ||
var chromosome2 = new Chromosome(this.NeuralNetwork.inputSize, this.NeuralNetwork.hiddenSize); | ||
|
||
chromosome1.setNeurons(c1); | ||
chromosome2.setNeurons(c2); | ||
|
||
return [chromosome1, chromosome2]; | ||
} | ||
|
||
copyChromosome(chromosomes) { | ||
if (!Array.isArray(chromosomes)) chromosomes = [chromosomes]; | ||
|
||
var newChromosomes = Array(); | ||
for (let i=0; i<chromosomes.length; i++) { | ||
|
||
var copied = Object.assign( | ||
Object.create( | ||
Object.getPrototypeOf(chromosomes[i]) | ||
), | ||
chromosomes[i] | ||
); | ||
|
||
copied.setNeurons(chromosomes[i].neurons); | ||
|
||
for (let k=0; k<copied.neurons.length; k++) { | ||
copied.neurons[k].clone = true; | ||
} | ||
|
||
newChromosomes.push(copied); | ||
} | ||
|
||
return newChromosomes; | ||
} | ||
|
||
sortChromosomes (a, b) { | ||
if (a.getFitness() > b.getFitness()) { | ||
return -1; | ||
} else if (a.getFitness() < b.getFitness()) { | ||
return 1; | ||
} | ||
|
||
return -1; | ||
} | ||
|
||
|
||
|
||
selectBestPopulation () { | ||
var actualGroup = this.population; | ||
actualGroup.sort(this.sortChromosomes); | ||
|
||
return actualGroup.slice(0,this.numberOfChromosomes); | ||
} | ||
|
||
//aAQUIUIIIIIIIIIIIII | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
class Chromosome { | ||
constructor (inputSize, size) { | ||
this.size = size; | ||
this.inputSize = inputSize; | ||
this.input = ''; | ||
this.fitness = 0; | ||
this.bias = 0; | ||
this.neurons = this.createNeurons(); | ||
} | ||
|
||
setBias (bias) { | ||
for (let i=0; i<this.size; i++) { | ||
this.neurons[i].setBias(bias); | ||
} | ||
this.bias = bias; | ||
} | ||
|
||
setNeurons (neurons) { | ||
if (!Array.isArray(neurons)) { | ||
console.error("Esse não é um Array de Neurons"); | ||
return false; | ||
} | ||
if (neurons.length != this.size) { | ||
console.error("Tamanho dos Neurons diferente (Chomosome)"); | ||
return false; | ||
} | ||
|
||
var n = Array(); | ||
for (let i=0; i<neurons.length; i++) { | ||
let nCopy = Object.assign( | ||
Object.create( | ||
Object.getPrototypeOf(neurons[i]) | ||
), | ||
neurons[i] | ||
); | ||
n.push(nCopy); | ||
} | ||
|
||
this.neurons = n; | ||
|
||
this.resetFitness(); | ||
} | ||
|
||
createNeurons () { | ||
var neurons = Array(); | ||
for (let i=0; i<this.size; i++) { | ||
neurons.push(new Neuron(this.inputSize, this.bias)); | ||
} | ||
return neurons; | ||
} | ||
|
||
setInput (input) { | ||
if (!Array.isArray(input)) input = [input]; | ||
if (input.length != this.inputSize) { | ||
console.error('Tamanho do input diferente (Chromosome)'); | ||
return false; | ||
} | ||
|
||
this.input = input; | ||
|
||
for (let i=0; i<this.neurons.length; i++) { | ||
this.neurons[i].setInput(input); | ||
} | ||
} | ||
|
||
calculate() { | ||
if (this.bias == 0) console.error("Bias não está definido (Chromosome)"); | ||
if (this.input.length === 0) { | ||
console.error('Input vazio (Chromosome)'); | ||
return false; | ||
} | ||
var results = Array(); | ||
for (let i=0; i<this.neurons.length; i++) { | ||
results.push(this.neurons[i].calculate()); | ||
} | ||
return results; | ||
} | ||
|
||
mutate (mutation, variation) { | ||
var pctUnique = 100 / this.neurons.length; | ||
var mutant = 0; | ||
var i = 0; | ||
while (mutant < mutation) { | ||
if (Math.random() > .7) { | ||
this.neurons[i].mutate(mutation, variation); | ||
mutant += pctUnique; | ||
} | ||
i++; | ||
if (i >= this.neurons.length) i = 0; | ||
} | ||
} | ||
|
||
setFitness (fitness) { | ||
this.fitness = fitness; | ||
} | ||
|
||
addFitness() { | ||
this.fitness++; | ||
} | ||
|
||
getFitness () { | ||
return this.fitness; | ||
} | ||
|
||
resetFitness () { | ||
this.fitness = 0; | ||
} | ||
|
||
print() { | ||
for (let i=0; i<this.neurons.length; i++) { | ||
this.neurons[i].print(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
class NeuralNetwork { | ||
constructor (inputSize, hiddenSize, outputSize, bias) { | ||
this.bias = bias; | ||
this.input = ''; | ||
this.inputSize = inputSize; | ||
this.outputSize = outputSize; | ||
this.hiddenSize = hiddenSize; | ||
|
||
this.createOutputLayer(); | ||
} | ||
|
||
setInput (input) { | ||
if (!Array.isArray(input)) input = [input]; | ||
if (input.length == this.inputSize) | ||
this.input = input; | ||
else | ||
console.error("Entrada tem tamanho diferente. (Neural Network)"); | ||
|
||
this.hiddenLayer.setInput(input); | ||
} | ||
|
||
calculate() { | ||
if (this.input.length === 0) { | ||
console.error('Input vazio (Neural Network)'); | ||
return false; | ||
} | ||
var resultHidden = this.hiddenLayer.calculate(); | ||
|
||
this.outputLayer.setInput(resultHidden); | ||
|
||
var resultOutput = this.outputLayer.calculate(); | ||
if (!resultOutput) { | ||
console.error("Erro ao calcular camada de saída", resultOutput); | ||
//return false; | ||
} | ||
|
||
//return resultOutput; | ||
return this.serializeResult(resultOutput); | ||
} | ||
|
||
serializeResult(result) { | ||
var r = Array(); | ||
for (let i=0; i<result.length; i++) { | ||
r.push(this.sigmoid(result[i])); | ||
} | ||
return r; | ||
} | ||
|
||
sigmoid (x) { | ||
return 1/(1+Math.pow(Math.E, -x)); | ||
} | ||
|
||
setHiddenLayer (hiddenLayer) { | ||
if (hiddenLayer instanceof Chromosome) { | ||
this.hiddenLayer = hiddenLayer; | ||
this.hiddenLayer.setBias(this.bias); | ||
} else | ||
console.error("Hidden Layer não é do tipo 'Chromosome'."); | ||
} | ||
|
||
createOutputLayer () { | ||
var outputLayer = new Chromosome(this.hiddenSize, this.outputSize); | ||
this.outputLayer = outputLayer; | ||
this.outputLayer.setBias(this.bias); | ||
return outputLayer; | ||
} | ||
|
||
addFitness () { | ||
this.hiddenLayer.addFitness(); | ||
} | ||
|
||
print() { | ||
console.table(this.input); | ||
this.hiddenLayer.print(); | ||
//console.table(); | ||
//console.table(this.outputLayer); | ||
} | ||
} |
Oops, something went wrong.