/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package automenta.spacenet.plugin.neural.brainz; import automenta.spacenet.var.Maths; import java.util.ArrayList; import java.util.List; /** * java port of critterding's BRAINZ system */ public class Brain { // input / output accessor/mutators List<SenseNeuron> sense = new ArrayList(); List<MotorNeuron> motor = new ArrayList(); List<InterNeuron> neuron = new ArrayList(); List<NeuronBuilder> neuronBuilders = new ArrayList(); // // BUILD TIME // int minNeuronsAtBuildtime; // // min/max neurons at build time // int maxNeuronsAtBuildtime; // // min/max neurons at build time // int maxNeurons; // // absolute max neurons (mutation bound) double percentChanceInhibitoryNeuron; // percent chance that when adding a new random neuron, it's inhibitory double percentChanceConsistentSynapses; // synaptic consistancy, meaning all synapses of a neuron will be OR I OR E: if set to 0, neurons will have mixed I and E synapses double percentChanceInhibitorySynapses; // // percent chance that when adding a new random neuron, it has inhibitory synapses double percentChanceMotorNeuron; // // percent chance that when adding a new random neuron, it has a motor function double percentChancePlasticNeuron; // // percent chance that when adding a new random neuron, it is has synaptic plasticity double minPlasticityStrengthen; // // min/max synaptic plasticity strengthening factor double maxPlasticityStrengthen; // // min/max synaptic plasticity strengthening factor double minPlasticityWeaken; // // min/max synaptic plasticity weakening factor double maxPlasticityWeaken; // // min/max synaptic plasticity weakening factor double minFiringThreshold; // // min/max firing threshold double maxFiringThreshold; // // min/max firing threshold double maxDendridicBranches; // // max dendritic branches in a new neuron double percentChanceSensorySynapse; // // percent chance that a new synapse is connected to a sensor neuron // int minSynapsesAtBuildtime; // // min/max synapses at build time // int maxSynapsesAtBuildtime; // // min/max synapses at build time int minSynapses; // // absolute min/max synapses (mutation/plastic bounding) int maxSynapses; // // absolute min/max synapses (mutation/plastic bounding) double percentMutation; // // brain architecture mutation factor @ mutation time (%) // // INFO // // total neuron & connection keepers int totalNeurons; int totalSynapses; // // after every time instance, this will contain how many neurons where fired in that instant (energy usage help) int neuronsFired; int motorneuronsFired; private final int numNeurons; public Brain(int neurons, int minSynapses, int maxSynapses) { super(); // build time defaults this.numNeurons = neurons; this.minSynapses = minSynapses; this.maxSynapses = maxSynapses; //totalNeurons = 0; //totalSynapses = 0; // minNeuronsAtBuildtime = 10; // maxNeuronsAtBuildtime = 150; // mutatables // minSynapsesAtBuildtime = 1; // maxSynapsesAtBuildtime = 50; percentChanceInhibitoryNeuron = 0.50; percentChanceConsistentSynapses = 0.50; percentChanceInhibitorySynapses = 0.50; percentChanceMotorNeuron = 0.50; percentChancePlasticNeuron = 0.50; minPlasticityStrengthen = 100; maxPlasticityStrengthen = 1000; minPlasticityWeaken = 1000; maxPlasticityWeaken = 10000; percentChanceSensorySynapse = 0.50; minFiringThreshold = 0.1; maxFiringThreshold = 1.0; maxDendridicBranches = 0.20; percentMutation = 0.01; } // RUN TIME public void clearInputs() { for (SenseNeuron sn : sense) { sn.senseInput = 0; } } public void clearOutputs() { // clear Motor Outputs for (MotorNeuron mn : motor) { mn.firing = false; } } public void forward() { // reset fired neurons counter neuronsFired = 0; motorneuronsFired = 0; clearOutputs(); //place sensory information in receiving InterNeurons // for (SenseNeuron n : sense) { // n.receiver.potential = n.output; // } for (InterNeuron n : neuron) { n.forward(); // if neuron fires if (n.nextOutput != 0) { neuronsFired++; //cerr << "neuron " << i << " fired " << n->waitoutput << endl; // motor neuron check & exec MotorNeuron mn = n.motor; if (mn != null) { motorneuronsFired++; mn.firing = true; //cerr << "neuron " << i << " fired, motor is " << Neurons[i]->MotorFunc << " total now " << Outputs[Neurons[i]->MotorFunc]->output << endl; } } } // commit outputs at the end for (InterNeuron in : neuron) { in.output = in.nextOutput; } } public void forwardUntilAnswer() { // // neuronsFired = 0; // // // clear Motor Outputs // for ( unsigned int i=0; i < numberOfOutputs; i++ ) // Outputs[i].output = false; // // // clear Neurons // for ( unsigned int i=0; i < totalNeurons; i++ ) // { // Neurons[i].output = 0; // Neurons[i].potential = 0.0f; // } // // unsigned int counter = 0; // bool motorFired = false; // // while ( counter < 1000 && !motorFired ) // { // for ( unsigned int i=0; i < totalNeurons; i++ ) // { // NeuronInterz* n = &Neurons[i]; // // n->process(); // // // if neuron fires // if ( n->waitoutput != 0 ) // { // neuronsFired++; // // // motor neuron check & exec // if ( n->isMotor ) // { // motorFired = true; // *Outputs[n->motorFunc].output = true; // //cerr << "neuron " << i << " fired, motor is " << Neurons[i]->MotorFunc << " total now " << Outputs[Neurons[i]->MotorFunc]->output << endl; // } // } // } // // commit outputs at the end // for ( unsigned int i=0; i < totalNeurons; i++ ) Neurons[i].output = Neurons[i].waitoutput; // // counter++; // } } MotorNeuron motor(int i) { return motor.get(i); } SenseNeuron sense(int i) { return sense.get(i); } public int getNumInputs() { return sense.size(); } public int getNumOutputs() { return motor.size(); } public MotorNeuron getRandomMotorNeuron() { return motor.get((int) Math.floor(Maths.random(0, motor.size()))); } public InterNeuron getRandomInterNeuron() { return neuron.get((int) Math.floor(Maths.random(0, neuron.size()))); } public SenseNeuron getRandomSenseNeuron() { return sense.get((int) Math.floor(Maths.random(0, sense.size()))); } // build time functions public NeuronBuilder newRandomNeuronBuilder() { // new architectural neuron NeuronBuilder an = new NeuronBuilder(); // is it inhibitory ? if (Math.random() <= percentChanceInhibitoryNeuron) { an.isInhibitory = true; } // if not, is it motor ? else if (Math.random() <= percentChanceMotorNeuron) { MotorNeuron mn = getRandomMotorNeuron(); // check if motor already used boolean proceed = true; for (NeuronBuilder nb : neuronBuilders) { if (nb.motor == mn) { proceed = false; break; } } if (proceed) { an.motor = mn; } } // does it have synaptic plasticity ? if (Math.random() <= percentChancePlasticNeuron) { an.isPlastic = true; an.plasticityStrengthen = Maths.random(minPlasticityStrengthen, maxPlasticityStrengthen); an.plasticityWeaken = Maths.random(minPlasticityWeaken, maxPlasticityWeaken); } // does it have consistent synapses ? if (Math.random() <= percentChanceConsistentSynapses) { an.hasConsistentSynapses = true; // if so, does it have inhibitory synapses ? if (Math.random() <= percentChanceInhibitorySynapses) { an.hasInhibitorySynapses = true; } } // determine firing threshold if (an.motor != null) { an.firingThreshold = maxFiringThreshold; } else { an.firingThreshold = Maths.random(minFiringThreshold, maxFiringThreshold); } // determine dendritic branches if (an.motor != null) { an.maxDendridicBranches = maxDendridicBranches; } else { an.maxDendridicBranches = (int) Math.round(Maths.random(1, maxDendridicBranches)); } // push it on the vector neuronBuilders.add(an); return an; } public SynapseBuilder newRandomSynapseBuilder(NeuronBuilder bn) { // new architectural synapse SynapseBuilder as = new SynapseBuilder(); // is it connected to a sensor neuron ? // < 2 because if only 1 archneuron, it can't connect to other one if (Math.random() <= percentChanceSensorySynapse || neuronBuilders.size() < 2) { as.isSensorNeuron = true; // sensor neuron id synapse is connected to as.senseNeuron = getRandomSenseNeuron(); } // if not determine inter neuron id else { // as in real life, neurons can connect to themselves //as.neuron = getRandomInterNeuron(); //randgen->Instance()->get( 0, ArchNeurons.size()-1 ); as.senseNeuron = null; } // dendrite branch number as.dendriteBranches = (int) Math.round(Maths.random(0.01, bn.maxDendridicBranches)); // synaptic weight if (bn.hasConsistentSynapses) { if (bn.hasInhibitorySynapses) { as.weight = -1.0f; } else { as.weight = 1.0f; } } else { if (Math.random() <= percentChanceInhibitorySynapses) { as.weight = -1.0f; } else { as.weight = 1.0f; } } bn.synapseBuilders.add(as); return as; } public MotorNeuron newOutput(/*bool* var, unsigned int id*/) { MotorNeuron m = new MotorNeuron(); motor.add(m); return m; } public SenseNeuron newInput() { SenseNeuron s = new SenseNeuron(); sense.add(s); return s; } public void removeObsoleteMotorsAndSensors() { // for ( int i = 0; i < (int)ArchNeurons.size(); i++ ) // { // ArchNeuronz* an = &ArchNeurons[i]; // // disable motor neurons // if ( an->isMotor ) // { // if ( findMotorNeuron( an->motorID ) == -1 ) // { // an->isMotor = false; // } // } // // // disable sensor inputs // for ( int j = 0; j < (int)an->ArchSynapses.size(); j++ ) // { // ArchSynapse* as = &an->ArchSynapses[j]; // if ( as->isSensorNeuron ) // { // if ( findSensorNeuron( as->neuronID ) == -1 ) // { // an->ArchSynapses.erase( an->ArchSynapses.begin()+j ); // j--; // } // } // } // } } public void buildArch() { // clear architecture by removing all architectural neurons neuronBuilders.clear(); // determine number of neurons this brain will start with //int numNeurons = (int) Math.round(Maths.random(minNeuronsAtBuildtime, maxNeuronsAtBuildtime)); // create the architectural neurons for (int i = 0; i < numNeurons; i++) { newRandomNeuronBuilder(); } // create architectural synapses for (NeuronBuilder n : neuronBuilders) { // determine amount of synapses this neuron will start with int SynapseAmount = (int) Math.round(Maths.random(minSynapses, maxSynapses)); // create the architectural neurons for (int j = 0; j < SynapseAmount; j++) { newRandomSynapseBuilder(n); } } } public void wireArch() { // clear everything neuron.clear(); //sense.clear(); //motor.clear(); // we know the amount of neurons already, reset totalsynapses for the count later totalNeurons = neuronBuilders.size(); totalSynapses = 0; // create all runtime neurons for (NeuronBuilder nb : neuronBuilders) { neuron.add(nb.newNeuron(maxSynapses)); } // create their synapses & link them to their inputneurons for (InterNeuron n : neuron) { for (SynapseBuilder sb : n.synapseBuilders) { AbstractNeuron i; if (sb.isSensorNeuron) { // sensor neuron id synapse is connected to i = getRandomSenseNeuron(); } // if not determine inter neuron id else { // as in real life, neurons can connect to themselves i = getRandomInterNeuron(); } n.newSynapse(i, n.dendridicBranches, sb.weight); } // count connections totalSynapses += n.synapses.size(); } // //cerr << "total neurons: " << totalNeurons << "total synapses: " << totalSynapses << endl; } public List<SenseNeuron> getSense() { return sense; } public List<MotorNeuron> getMotor() { return motor; } public List<InterNeuron> getNeuron() { return neuron; } public int getTotalNeurons() { return totalNeurons; } public int getTotalSynapses() { return totalSynapses; } // // load save architecture (serialize) // void setArch(string* content); // string* getArch(); // // // build commands // // functions // void copyFrom(const Brainz& otherBrain); // void mergeFrom(const Brainz& otherBrain1, const Brainz& otherBrain2); }