📄 cherrymoya.cpp
字号:
/*************************************************************************** cherrymoya.cpp - description ------------------- begin : Sat Jan 19 2002 copyright : (C) 2002 by Rudiger Koch email : rkoch@rkoch.org ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "cherrymoya.h"#include "fastneuron.h"#include "layer.h"#include <cmath>#include <iostream>Cherrymoya::Cherrymoya(unsigned int r){ radius = r; dendriteRadius = 1.; stepSize = 0.2; offset = 0.4; axonLengthFactor = 4; N_chromosome = 0; net = new Network; layerConst.learningConst = 1e-3; // was: 1e-3 layerConst.membraneTimeConst = 10.0; // was: 10.0 layerConst.synapticTimeConst = 2.0; // was: 2.0 layerConst.restPtnl = 0.0; // was: 0.0 layerConst.thresholdPtnl = 5.0; // was: 5.0 layerConst.type = INPUTLAYER; layerConst.layerId = 1; inputLayer = new Layer(); inputLayer->SetLayerConstants(layerConst); inputLayer->LayerName("InputLayer"); layerConst.type = HIDDENLAYER; layerConst.layerId = 2; hiddenLayer = new Layer(); hiddenLayer->SetLayerConstants(layerConst); hiddenLayer->LayerName("TheSkinAndTheMeat"); layerConst.type = OUTPUTLAYER; layerConst.layerId = 3; outputLayer = new Layer(); outputLayer->SetLayerConstants(layerConst); outputLayer->LayerName("OutputLayer"); nId = 1; BuildCherrymoya(); synapses = 0;}Cherrymoya::~Cherrymoya(){}void Cherrymoya::startChromosome(int geneLength, int genes){ N_chromosome++; if(N_chromosome > 3 ) throw string("unknown chromosome"); N_gene = 0;}void Cherrymoya::gene(string gene){ unsigned char uc; N_gene++; float phi = gene[0] * M_PI / 128.; float theta = gene[1] * M_PI / 128.; float strength; float r; switch(N_chromosome) { case SKIN: strength = gene[2] / 128.; // between -1 and +1 r = radius + offset; break; case OUT: uc = gene[3]; strength = - float(unsigned(uc)) / 256.; // pours at input neurons r = gene[2] / 128. * (radius + offset - 1); break; case IN: uc = gene[3]; strength = float(unsigned(uc)) / 256.; // sinks at output neurons r = gene[2] / 128. * (radius + offset - 1); break; default: throw string("unknown chromosome"); } float x = cos(phi) * sin(theta) * r; float y = sin(phi) * sin(theta) * r; float z = cos(theta) * r; pair < float, Neuron*> singularity; Neuron *tmpNeuron; if(N_chromosome != SKIN) { // The skin singularities don't go with I/O neurons tmpNeuron = new FastNeuron(nId++); tmpNeuron->SetLearningConst(layerConst.learningConst); tmpNeuron->SetTimeConstants(layerConst.synapticTimeConst, layerConst.membraneTimeConst); tmpNeuron->SetRestPotential(layerConst.restPtnl); tmpNeuron->SetThresholdPotential(layerConst.thresholdPtnl); float location [3]; location [0] = x; location [1] = y; location [2] = z; PhysicalProperties *props = tmpNeuron->GetPhysicalProperties(); props->SetLocation(location); singularity.first = strength; singularity.second = tmpNeuron; } float *skinSingularity; switch(N_chromosome) { case SKIN: skinSingularity = new float[3]; skinSingularity[0] = strength; skinSingularity[1] = phi; skinSingularity[2] = theta; skinSingularities.push_back(skinSingularity); break; case IN: inputLayer->AddNeuron(tmpNeuron); inputNeurons.push_back(singularity); break; case OUT: outputLayer->AddNeuron(tmpNeuron); outputNeurons.push_back(singularity); break; default: break; }}const int& Cherrymoya::getradius(){ return radius;}void Cherrymoya::BuildCherrymoya(){ // We buildup the sphere by traversing each block of the qube around the // sphere. If a block is within the radius, a skin neuron is placed there. // If a block is within r = radius-1 a meat neuron is placed const float outerRadius = radius + offset; const float innerRadius = radius + offset - 1; for (int x = -radius; x <= radius; x++){ vector < vector <pair <bool, Neuron * > > > yVector; theCherrymoya.push_back(yVector); for (int y = -radius; y <= radius; y++){ vector <pair <bool, Neuron * > > zVector; theCherrymoya[x+radius].push_back(zVector); for (int z = -radius; z <= radius; z++){ float neuronRadius = sqrt(float(x*x + y*y + z*z)); if(neuronRadius < outerRadius){ Neuron *tmpNeuron = new FastNeuron(nId++); tmpNeuron->SetLearningConst(layerConst.learningConst); tmpNeuron->SetTimeConstants(layerConst.synapticTimeConst, layerConst.membraneTimeConst); tmpNeuron->SetRestPotential(layerConst.restPtnl); tmpNeuron->SetThresholdPotential(layerConst.thresholdPtnl); hiddenLayer->AddNeuron(tmpNeuron); float location [] = {(float)x, (float)y, (float)z }; PhysicalProperties *props = tmpNeuron->GetPhysicalProperties(); props->SetLocation(location); if(neuronRadius > innerRadius){ // skin neuron pair<bool, Neuron*> n(true, tmpNeuron); theCherrymoya[x+radius][y+radius].push_back(n); } else { // meat neuron pair<bool, Neuron*> n(false, tmpNeuron); theCherrymoya[x+radius][y+radius].push_back(n); } } else { pair<bool, Neuron*> n = pair<bool, Neuron*>(true, NULL); theCherrymoya[x+radius][y+radius].push_back(n); } } } }}void Cherrymoya::finish(){ net->AddLayer(inputLayer); net->AddLayer(outputLayer); net->AddLayer(hiddenLayer); connectSkin(); connectMeat(); connectInputNeurons(); cout << "Network generated: " << nId << " neurons, " << synapses << " synapses" << endl;}Network* Cherrymoya::getNetwork(){ return net;}void Cherrymoya::connectSkin(){ for (int x = -radius; x <= radius; x++){ for (int y = -radius; y <= radius; y++){ for (int z = -radius; z <= radius; z++){ if(theCherrymoya[x+radius][y+radius][z+radius].second == NULL) continue; if(theCherrymoya[x+radius][y+radius][z+radius].first == false) continue; AxonConnectorSkin(theCherrymoya[x+radius][y+radius][z+radius].second); } } }}void Cherrymoya::connectMeat(){ for (int x = -radius; x <= radius; x++){ for (int y = -radius; y <= radius; y++){ for (int z = -radius; z <= radius; z++){ if(theCherrymoya[x+radius][y+radius][z+radius].second == NULL) continue; if(theCherrymoya[x+radius][y+radius][z+radius].first == true) continue; AxonConnector3D(theCherrymoya[x+radius][y+radius][z+radius].second); } } }}void Cherrymoya::connectInputNeurons(){ for(unsigned int i=0; i<inputNeurons.size(); i++){ AxonConnector3D(inputNeurons[i].second); }}void Cherrymoya::getFieldStrengthMeat(float *location, float *E){ E[0] = 0.; E[1] = 0.; E[2] = 0.; for(unsigned int i=0; i<outputNeurons.size(); i++){ PhysicalProperties *props = outputNeurons[i].second->GetPhysicalProperties(); float nLoc[3]; props->GetLocation(nLoc); float r[3]; for (unsigned int j=0; j<3; j++) r[j] = location[j] - nLoc[j]; float div = r[0]*r[0] + r[1]*r[1] + r[2]*r[2]; if(div < 0.3) div = 0.2; float constants = outputNeurons[i].first / div; for (unsigned int j=0; j<3; j++) E[j] += constants * r[j]; } for(unsigned int i=0; i<inputNeurons.size(); i++){ PhysicalProperties *props = inputNeurons[i].second->GetPhysicalProperties(); float nLoc[3]; props->GetLocation(nLoc); float r[3]; for (unsigned int j=0; j<3; j++) r[j] = location[j] - nLoc[j]; float div = r[0]*r[0] + r[1]*r[1] + r[2]*r[2]; if(div < 0.3) div = 0.2; float constants = inputNeurons[i].first / div; for (unsigned int j=0; j<3; j++) E[j] += constants * r[j]; } for (unsigned int i=0; i<3; i++) { // make sure E doesn't get too big close to a singularity if(E[i] > radius) E[i] = radius; if(E[i] < -radius) E[i] = -radius; }}// FIXME: The whole function is junk (both it's semantics and it's implementation)void Cherrymoya::AxonConnector3D(Neuron *currentNeuron){ float axonTraverser[3], E[3]; float weight; float ourLoc[3]; currentNeuron->GetPhysicalProperties()->GetLocation(ourLoc); for(int i=0; i<3;i++)axonTraverser[i] = ourLoc[i]; vector < unsigned int > axon; // remember who we already connected to unsigned int ourId = currentNeuron->GetID(); axon.push_back(ourId); // and make sure we don't connect to ourselves getFieldStrengthMeat(axonTraverser, E); const float axonLength = axonLengthFactor * sqrt(E[0]*E[0] + E[1]*E[1] + E[2]*E[2]); float axonPos = 0; // current position on the axon in axon coordinates while(axonPos < axonLength){ Neuron *postN; float direction[3]; getFieldStrengthMeat(axonTraverser, direction); float length = sqrt(direction[0] * direction[0] + direction[1] * direction[1] + direction[2] * direction[2]); axonPos += stepSize; if(axonPos > dendriteRadius) weight = 0.5; // FIXME: AD HOC!!!! else weight = -0.5; for(int i=0; i<3;i++) axonTraverser[i] += direction[i] * stepSize / length; // is there an output neuron? for(unsigned int i=0; i<outputNeurons.size(); i++){ PhysicalProperties *props = outputNeurons[i].second->GetPhysicalProperties(); float nLoc[3]; props->GetLocation(nLoc); float distance = sqrt((axonTraverser[0] - nLoc[0]) * (axonTraverser[0] - nLoc[0]) + (axonTraverser[1] - nLoc[1]) * (axonTraverser[1] - nLoc[1]) + (axonTraverser[2] - nLoc[2]) * (axonTraverser[2] - nLoc[2])); if(distance < dendriteRadius) { for(unsigned int j=0; j<axon.size(); j++){ if(axon[j] == outputNeurons[i].second->GetID()) goto FIXME1; // already connected } axon.push_back(outputNeurons[i].second->GetID()); net->ConnectNeurons(ourId, outputNeurons[i].second->GetID(), weight); // FIXME: variabe weights synapses++; } }FIXME1: for (int x = -radius; x <= radius; x++){ for (int y = -radius; y <= radius; y++){ for (int z = -radius; z <= radius; z++){ if(theCherrymoya[x+radius][y+radius][z+radius].second == NULL) continue; float distance = sqrt((x - axonTraverser[0]) * (x - axonTraverser[0]) + (y - axonTraverser[1]) * (y - axonTraverser[1]) + (z - axonTraverser[2]) * (z - axonTraverser[2])); if(distance < dendriteRadius) { postN = theCherrymoya[x+radius][y+radius][z+radius].second; if(postN != NULL) { for(unsigned int i=0; i<axon.size(); i++){ if(axon[i] == postN->GetID()) goto FIXME; // already connected } synapses++; net->ConnectNeurons(ourId, postN->GetID(), weight); // FIXME: variabe weights axon.push_back(postN->GetID()); } } } } }FIXME: continue; // no comment on this - this function MUST be re-implemented }}void Cherrymoya::getFieldStrengthSkin(float *location, float *E){ E[0] = 0.; E[1] = 0.; // Bronstein S.217 const float phi_n = atan(location[1] / location[0]); const float theta_n = atan(sqrt(location[1]*location[1] + location[0]*location[0]) / location[2]); for(unsigned int i=0; i<skinSingularities.size(); i++){ const float strenght = skinSingularities[i][0]; const float phi_s = skinSingularities[i][1]; const float theta_s = skinSingularities[i][2]; // calculate the distance according to Bronstein, 3.197 (S.172) const float distance = radius * acos(sin(phi_n)*sin(phi_s) + cos(phi_n)*cos(phi_s)*cos(theta_s - theta_n));// TODO: do the rest of the calculation }}void Cherrymoya::AxonConnectorSkin(Neuron *currentNeuron){ float ourLoc[3]; float shadowLoc[3]; currentNeuron->GetPhysicalProperties()->GetLocation(ourLoc); // Bronstein S.217 - 3.355a const float phi = atan(ourLoc[1] / ourLoc[0]); const float theta = atan(sqrt(ourLoc[1]*ourLoc[1] + ourLoc[0]*ourLoc[0]) / ourLoc[2]); shadowLoc[0] = sin(theta)*cos(phi)*radius / 4.; shadowLoc[1] = sin(theta)*sin(phi)*radius / 4.; shadowLoc[2] = cos(theta)*radius / 4.; currentNeuron->GetPhysicalProperties()->SetLocation(shadowLoc); AxonConnector3D(currentNeuron); currentNeuron->GetPhysicalProperties()->SetLocation(ourLoc);}vector <AmIdInt> Cherrymoya::GetInputNeurons(){ vector <AmIdInt> iNeurons; for (unsigned int i=0; i<inputNeurons.size(); i++){ iNeurons.push_back(inputNeurons[i].second->GetID()); } return iNeurons;}vector <Neuron*> Cherrymoya::GetOutputNeurons(){ vector <Neuron*> oNeurons; for (unsigned int i=0; i<outputNeurons.size(); i++){ oNeurons.push_back(outputNeurons[i].second); } return oNeurons;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -