Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

ConnectionMatrixLoader.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Application                                               *
00003  *   Copyright (C) 2007 by David Gamez                                     *
00004  *   david@davidgamez.eu                                                   *
00005  *   Version 0.1                                                           *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 
00023 //SpikeStream includes
00024 #include "ConnectionMatrixLoader.h"
00025 #include "Debug.h"
00026 #include "Utilities.h"
00027 #include "ConnectionType.h"
00028 #include "NeuronGroupType.h"
00029 
00030 //Qt includes 
00031 #include <qmessagebox.h>
00032 #include <qfile.h>
00033 
00034 //Other includes
00035 #include <mysql++.h>
00036 #include <cmath>
00037 using namespace std;
00038 using namespace mysqlpp;
00039 
00040 
00041 //Local debug defines
00042 #define LOAD_CONNECTION_MATRIX_DEBUG
00043 
00044 
00045 /*! Constructor. */
00046 ConnectionMatrixLoader::ConnectionMatrixLoader(DBInterface* netDBInter){
00047         //Store references
00048         networkDBInterface = netDBInter;
00049 }
00050 
00051 
00052 /*! Destructor. */
00053 ConnectionMatrixLoader::~ConnectionMatrixLoader(){
00054         #ifdef MEMORY_DEBUG
00055                 cout<<"DELETING CONNECTION MATRIX LOADER"<<endl;
00056         #endif//MEMORY_DEBUG
00057 }
00058 
00059 
00060 //--------------------------------------------------------------------------------
00061 //---------                     PUBLIC METHODS                           ---------
00062 //--------------------------------------------------------------------------------
00063 
00064 /*! Loads a connection matrix from the file into the database. */
00065 bool ConnectionMatrixLoader::loadConnectionMatrix(QString& fileName){
00066         //Initialise class variables
00067         neurGrpID = 0;
00068         connGrpID = 0;
00069         neuronType = 0;
00070         synapseType = 0;
00071         neurGrpWidth = 0;
00072         neurGrpLength = 0;
00073         neurParamTable = "";
00074         numNeur = 0;
00075         connectionCount = 0;
00076         rowNum = 0;
00077         errorState = false;
00078         
00079         //Need to create neuron and connection groups once we know size
00080         bool firstLine = true;
00081 
00082         //Create file with fileName
00083         QFile file(fileName);
00084 
00085         //Read in pattern
00086         if ( file.open( IO_ReadOnly ) ) {
00087                 QTextStream stream( &file );
00088                 QString fileLine;
00089 
00090                 while ( !stream.atEnd() && !errorState) {
00091                         fileLine = stream.readLine(); // line of text excluding '\n'
00092                         #ifdef LOAD_CONNECTION_MATRIX_DEBUG
00093                                 cout<<"Reading line: \""<<fileLine<<"\""<<endl;
00094                         #endif//LOAD_PATTERN_DEBUG
00095 
00096                         //Get the line and split it into neuron ids.
00097                         QStringList neuronList = QStringList::split(",", fileLine);
00098 
00099                         #ifdef LOAD_CONNECTION_MATRIX_DEBUG
00100                                 cout<<"Matrix contains "<<numNeur<<" neurons."<<endl;
00101                         #endif//LOAD_PATTERN_DEBUG
00102 
00103                         //Set up neuron and connection groups
00104                         if(firstLine){
00105                                 //Store number of neurons
00106                                 numNeur = neuronList.size();
00107 
00108                                 //Create the neuron group
00109                                 createNeuronGroup();
00110                                 if(neurGrpID == 0 || errorState){//An error has occured
00111                                         file.close();
00112                                         deleteDatabaseEntries(neurGrpID, connGrpID);
00113                                         return false;
00114                                 }
00115         
00116                                 //Create connection group to add connections
00117                                 createConnectionGroup(fileName);
00118                                 if(connGrpID == 0 || errorState){//An error has occured
00119                                         file.close();
00120                                         deleteDatabaseEntries(neurGrpID, connGrpID);
00121                                         return false;
00122                                 }
00123 
00124                                 //Have now set up appropriate neuron and connection groups
00125                                 firstLine = false;
00126                         }
00127 
00128                         //Add connections from first line that has been read in
00129                         addConnections(neuronList);
00130                         ++rowNum;
00131 
00132                 }
00133                 //Close file
00134                 file.close();
00135 
00136                 //Check that matrix is square
00137                 if(rowNum != numNeur){
00138                         deleteDatabaseEntries(neurGrpID, connGrpID);
00139                         showError("ConnectionMatrixLoader: Matrix not square");
00140                         return false;
00141                 }
00142 
00143                 //Check that we have not encountered any errors
00144                 if(errorState){
00145                         deleteDatabaseEntries(neurGrpID, connGrpID);
00146                         return false;
00147                 }
00148 
00149                 /* Check that we have added at least one connection.
00150                         If not, get rid of connection group entry because it is not needed.*/
00151                 try{
00152                         Query query = networkDBInterface->getQuery();
00153                         if(connectionCount == 0){
00154                                 query.reset();
00155                                 query<<"DELETE FROM ConnectionGroups WHERE ConnGrpID = "<<connGrpID;
00156                                 query.execute();
00157                         }
00158                         else{//Add entry to parameter table for this connection group.*/
00159                                 //Find the appropriate table
00160                                 query.reset();
00161                                 query<<"SELECT ParameterTableName FROM SynapseTypes WHERE TypeID = "<<synapseType;
00162                                 Result tableNameRes = query.store();
00163                                 Row tableNameRow (*tableNameRes.begin());//Should only be 1 row
00164                         
00165                                 //Add an entry for this connection group to the appropriate table
00166                                 query.reset();
00167                                 query<<"INSERT INTO "<<(std::string)tableNameRow["ParameterTableName"]<<" (ConnGrpID) VALUES ("<<connGrpID<<")";
00168                                 query.execute();
00169                         }
00170                 }
00171                 catch (const BadQuery& er) {// Handle any query errors
00172                         QString errorString = "ConnectionMatrixLoader: MySQL++ BadQuery thrown creating neuron group: \"";
00173                         errorString += er.what();
00174                         errorString += "\"";
00175                         showError(errorString);
00176                         deleteDatabaseEntries(neurGrpID, connGrpID);
00177                         return false;
00178                 }
00179                 catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00180                         QString errorString = "ConnectionMatrixLoader: MySQL++ Exception thrown creating neuron group: \"";
00181                         errorString += er.what();
00182                         errorString += "\"";
00183                         showError(errorString);
00184                         deleteDatabaseEntries(neurGrpID, connGrpID);
00185                         return false;
00186                 }
00187                 catch(std::exception& er){// Catch-all for any other exceptions
00188                         QString errorString = "ConnectionMatrixLoader: std::exception thrown creating neuron group\"";
00189                         errorString += er.what();
00190                         errorString += "\"";
00191                         showError(errorString);
00192                         deleteDatabaseEntries(neurGrpID, connGrpID);
00193                         return false;
00194                 }
00195                 
00196                 #ifdef LOAD_CONNECTION_MATRIX_DEBUG
00197                         cout<<"Connection matrix loading complete. "<<connectionCount<<" connections loaded. "<<endl;
00198                 #endif//LOAD_PATTERN_DEBUG
00199         }
00200         else{
00201                 showError("ConnectionMatrixLoader: Error opening file.");
00202                 return false;
00203         }
00204 
00205         //Everything should be ok if we have got to this point.
00206         return true;
00207 }
00208 
00209 
00210 //--------------------------------------------------------------------------------
00211 //---------                     PRIVATE METHODS                          ---------
00212 //--------------------------------------------------------------------------------
00213 
00214 /*! Adds the connections to the database.       */
00215 void ConnectionMatrixLoader::addConnections(QStringList& neuronIDList){
00216         try{
00217                 Query query = networkDBInterface->getQuery();
00218                 double connWeight;
00219 
00220                 /* Work through all the connections between the current row number and the
00221                         column numbers.*/
00222                 for(unsigned int colNum=0; colNum<neuronIDList.size(); ++colNum){
00223                         connWeight = Utilities::getDouble(neuronIDList[colNum].ascii());//Weight between 0.0 and 1.0
00224                         connWeight *= 127.0;//Weight between 0.0 and 127.0
00225                         if(connWeight > 0){
00226                                 /* Add a connection. This is between the neuron id at the current row 
00227                                         and the neuron id at colNum.*/
00228                                 query.reset();
00229                                 query<<"INSERT INTO Connections (PreSynapticNeuronID, PostSynapticNeuronID, Delay, Weight, ConnGrpID) VALUES ("<<(startNeurID + rowNum)<<", "<<(startNeurID + colNum)<<", "<<0<<", "<<connWeight<<", "<<connGrpID<<")";
00230                                 query.execute();
00231                                 ++connectionCount;
00232                         }
00233                 }
00234         }
00235         catch (const BadQuery& er) {// Handle any query errors
00236                 QString errorString = "ConnectionMatrixLoader: MySQL++ BadQuery thrown creating neuron group: \"";
00237                 errorString += er.what();
00238                 errorString += "\"";
00239                 showError(errorString);
00240         }
00241         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00242                 QString errorString = "ConnectionMatrixLoader: MySQL++ Exception thrown creating neuron group: \"";
00243                 errorString += er.what();
00244                 errorString += "\"";
00245                 showError(errorString);
00246         }
00247         catch(std::exception& er){// Catch-all for any other exceptions
00248                 QString errorString = "ConnectionMatrixLoader: std::exception thrown creating neuron group\"";
00249                 errorString += er.what();
00250                 errorString += "\"";
00251                 showError(errorString);
00252         }
00253 }
00254 
00255 
00256 /*! Creates a connection group internal to the specified neuron group.
00257         Returns the connection group id.*/
00258 void ConnectionMatrixLoader::createConnectionGroup(const QString& fileName){
00259         /* Create the xml string to hold the parameters of the connection.
00260                 This holds all the information about the connection that is not included elsewhere
00261                 in the connection group table.*/
00262         ostringstream xmlStrStream;
00263         xmlStrStream<<"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
00264         xmlStrStream<<"<connection_parameters>";
00265 
00266         //Add file name as the only parameter
00267         xmlStrStream<<"<parameter>";
00268         xmlStrStream<<"<description>"<<"Connection Matrix file name"<<"</description>";
00269         xmlStrStream<<"<value>"<<fileName<<"</value>";
00270         xmlStrStream<<"</parameter>";
00271         xmlStrStream<<"</connection_parameters>";
00272 
00273         try{
00274                 Query query = networkDBInterface->getQuery();
00275 
00276                 //Find the first synapse type
00277                 query.reset();
00278                 query<<"SELECT MIN(TypeID) from SynapseTypes";
00279                 Result minTypeIDRes = query.store();
00280                 Row minTypeIDRow(*(minTypeIDRes.begin()));
00281                 synapseType = Utilities::getUInt((std::string)minTypeIDRow["MIN(TypeID)"]);
00282 
00283                 //Create connection group
00284                 query.reset();
00285                 ostringstream strbuf;
00286                 strbuf<<"INSERT INTO ConnectionGroups (FromNeuronGrpID, ToNeuronGrpID, ConnType, SynapseType, Parameters) VALUES ("<<neurGrpID<<", "<<neurGrpID<<", "<<ConnectionType::SimpleCortex<<", "<<synapseType<<", \""<<mysqlpp::escape<<xmlStrStream.str()<<"\" )";
00287                 query.exec(strbuf.str());
00288                 
00289                 //Get the automatically generated ConnGrpID so that it can be added to the new connections
00290                 query.reset();
00291                 query<<"SELECT MAX(ConnGrpID) from ConnectionGroups";
00292                 Result grpIDResult = query.store();
00293                 Row row(*(grpIDResult.begin()));
00294                 connGrpID = Utilities::getUInt((string)row["MAX(ConnGrpID)"]);
00295         }
00296         catch (const BadQuery& er) {// Handle any query errors
00297                 QString errorString = "ConnectionMatrixLoader: MySQL++ BadQuery thrown creating neuron group: \"";
00298                 errorString += er.what();
00299                 errorString += "\"";
00300                 showError(errorString);
00301         }
00302         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00303                 QString errorString = "ConnectionMatrixLoader: MySQL++ Exception thrown creating neuron group: \"";
00304                 errorString += er.what();
00305                 errorString += "\"";
00306                 showError(errorString);
00307         }
00308         catch(std::exception& er){// Catch-all for any other exceptions
00309                 QString errorString = "ConnectionMatrixLoader: std::exception thrown creating neuron group\"";
00310                 errorString += er.what();
00311                 errorString += "\"";
00312                 showError(errorString);
00313         }
00314 }
00315 
00316 
00317 /*! Creates a neuron group and its associated neurons.
00318         Returns the neuron id.*/
00319 void ConnectionMatrixLoader::createNeuronGroup(){
00320         int neuronCount = 0;
00321         try{
00322                 Query query = networkDBInterface->getQuery();
00323 
00324                 //Work out the width and length of the neuron group - ideally make it square
00325                 neurGrpWidth = (unsigned int)floor(sqrt(numNeur));
00326                 neurGrpLength = numNeur/neurGrpWidth;
00327 
00328                 //Double check width and length make sense
00329                 if( (neurGrpWidth * neurGrpLength) != numNeur){
00330                         showError("Neuron width * length does not equal number of neurons.");
00331                         return;
00332                 }
00333 
00334                 #ifdef LOAD_CONNECTION_MATRIX_DEBUG
00335                         cout<<"Neuron group width =  "<<neurGrpWidth<<"; neuron group length = "<<neurGrpLength<<endl;
00336                 #endif//LOAD_PATTERN_DEBUG
00337 
00338                 //Get all layers with this z coordinate
00339                 query.reset();
00340                 query<<"SELECT NeuronID FROM Neurons WHERE X >="<<0<<" AND X <= "<<neurGrpWidth<<" AND Y >= "<<0<<" AND Y <= "<<neurGrpLength<<" AND Z = "<<0;
00341                 Result zLayerResult = query.store();
00342                 if(zLayerResult.size() > 0){
00343                         showError("ConnectionMatrixLoader: CONFLICT WITH EXISTING LAYERS");
00344                         return;
00345                 }
00346         
00347                 //Only reach this point if there are no conflicts with existing layers
00348                 //Get the first neuron type in the NeuronTypes database
00349                 query.reset();
00350                 query<<"SELECT MIN(TypeID) from NeuronTypes";
00351                 Result minTypeIDRes = query.store();
00352                 Row minTypeIDRow(*(minTypeIDRes.begin()));
00353                 neuronType = Utilities::getUInt((std::string)minTypeIDRow["MIN(TypeID)"]);
00354 
00355                 //Add layer entry to layer database
00356                 query.reset();
00357                 query<<"INSERT INTO NeuronGroups (Name, NeuronGrpType, NeuronType, X, Y, Z, Width, Length, Spacing, TaskID) VALUES (\""<<"Untitled"<<"\", "<<NeuronGroupType::RectangularLayer2D<<", "<<neuronType<<", "<<0<<", "<<0<<", "<<0<<", "<<neurGrpWidth<<", "<<neurGrpLength<<", "<<1<<", -1)";
00358                 query.execute();
00359                 
00360                 //Now need to get the automatically generated NeuronGrpID so that it can be added to the neurons in the new layers
00361                 query.reset();
00362                 query<<"SELECT MAX(NeuronGrpID) from NeuronGroups";
00363                 Result neurGrpIDRes = query.store();
00364                 Row neurGrpIDRow(*(neurGrpIDRes.begin()));
00365                 neurGrpID = Utilities::getUInt((std::string)neurGrpIDRow["MAX(NeuronGrpID)"]);
00366 
00367                 /* Add neurons to neuron database. 
00368                         This adds them in a scanning pattern moving horizontally along the x axis 
00369                         before moving to the next line */
00370                 for(unsigned int i=0; i<neurGrpLength; ++i){
00371                         for(unsigned int j=0; j<neurGrpWidth; ++j){
00372                                 query.reset();
00373                                 query<<"INSERT INTO Neurons (X, Y, Z, NeuronGrpID) VALUES ("<<j<<", "<<i<<", "<<0<<", "<<neurGrpID<<")";
00374                                 query.execute();
00375                                 ++neuronCount;
00376                         }
00377                 }
00378 
00379                 //Get the lowest neuron id in this group.
00380                 query.reset();
00381                 query<<"SELECT MIN(NeuronID) from Neurons WHERE NeuronGrpID = "<<neurGrpID;
00382                 Result startIDRes = query.store();
00383                 Row startIDRow(*(startIDRes.begin()));
00384                 startNeurID = Utilities::getUInt((std::string)startIDRow["MIN(NeuronID)"]);
00385 
00386                 //Add parameter and noise entries for this neuron group
00387                 //Find the appropriate table
00388                 query.reset();
00389                 query<<"SELECT ParameterTableName FROM NeuronTypes WHERE TypeID = "<<neuronType;
00390                 Result tableNameRes = query.store();
00391                 Row tableNameRow (*tableNameRes.begin());//Should only be 1 row
00392                 neurParamTable = (std::string)tableNameRow["ParameterTableName"];
00393                 
00394                 //Now add an entry for this neuron group to the appropriate table
00395                 query.reset();
00396                 query<<"INSERT INTO "<<neurParamTable<<" (NeuronGrpID) VALUES ("<<neurGrpID<<")";
00397                 query.execute();
00398         
00399                 //Add entry for this layer to the noise parameters table
00400                 query.reset();
00401                 query<<"INSERT INTO NoiseParameters (NeuronGrpID) VALUES ("<<neurGrpID<<")";
00402                 query.execute();
00403 
00404         }
00405         catch (const BadQuery& er) {// Handle any query errors
00406                 QString errorString = "ConnectionMatrixLoader: MySQL++ BadQuery thrown creating neuron group: \"";
00407                 errorString += er.what();
00408                 errorString += "\"";
00409                 showError(errorString);
00410                 deleteDatabaseEntries(neurGrpID, 0);
00411         }
00412         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00413                 QString errorString = "ConnectionMatrixLoader: MySQL++ Exception thrown creating neuron group: \"";
00414                 errorString += er.what();
00415                 errorString += "\"";
00416                 showError(errorString);
00417                 deleteDatabaseEntries(neurGrpID, 0);
00418         }
00419         catch(std::exception& er){// Catch-all for any other exceptions
00420                 QString errorString = "ConnectionMatrixLoader: std::exception thrown creating neuron group\"";
00421                 errorString += er.what();
00422                 errorString += "\"";
00423                 showError(errorString);
00424                 deleteDatabaseEntries(neurGrpID, 0);
00425         }
00426 
00427         #ifdef LOAD_CONNECTION_MATRIX_DEBUG
00428                 cout<<neuronCount<<" neurons added to database."<<endl;
00429         #endif//LOAD_CONNECTION_MATRIX_DEBUG
00430 }
00431 
00432 
00433 /*! Cleans up the database when an error occurs.*/
00434 void ConnectionMatrixLoader::deleteDatabaseEntries(unsigned int nGrpID, unsigned int cGrpID){
00435         try{
00436                 Query query = networkDBInterface->getQuery();
00437 
00438                 //Check to see if neuron group has been created.
00439                 if(neurGrpID > 0){
00440                         //Delete neurons
00441                         query.reset();
00442                         query<<"DELETE FROM Neurons WHERE NeuronGrpID = "<<nGrpID;
00443                         query.execute();
00444 
00445                         //Delete neuron group
00446                         query.reset();
00447                         query<<"DELETE FROM NeuronGroups WHERE NeuronGrpID = "<<nGrpID;
00448                         query.execute();
00449 
00450                         //Delete parameters if they have been added
00451                         if(neurParamTable != ""){
00452                                 query.reset();
00453                                 query<<"DELETE FROM "<<neurParamTable<<" WHERE NeuronGrpID = "<<nGrpID;
00454                                 query.execute();
00455                         }
00456 
00457                         //Delete entry from noise table
00458                         query.reset();
00459                         query<<"DELETE FROM NoiseParameters WHERE NeuronGrpID = "<<nGrpID;
00460                         query.execute();
00461 
00462                         //Reset neurGrpID
00463                         neurGrpID = 0;
00464                 }
00465         
00466                 //Check to see if connection group has been created
00467                 if(connGrpID > 0){
00468                         //Delete connections
00469                         query.reset();
00470                         query<<"DELETE FROM Connections WHERE ConnGrpID = "<<cGrpID;
00471                         query.execute();
00472 
00473                         //Delete connection group
00474                         query.reset();
00475                         query<<"DELETE FROM ConnectionGroups WHERE ConnGrpID = "<<cGrpID;
00476                         query.execute();
00477 
00478                         //Reset connGrpID
00479                         connGrpID = 0;
00480                 }
00481         }
00482         catch (const BadQuery& er) {// Handle any query errors
00483                 QString errorString = "ConnectionMatrixLoader: MySQL++ BadQuery thrown deleting database entries: \"";
00484                 errorString += er.what();
00485                 errorString += "\"";
00486                 showError(errorString);
00487         }
00488         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00489                 QString errorString = "ConnectionMatrixLoader: MySQL++ Exception thrown deleting database entries: \"";
00490                 errorString += er.what();
00491                 errorString += "\"";
00492                 showError(errorString);
00493         }
00494         catch(std::exception& er){// Catch-all for any other exceptions
00495                 QString errorString = "ConnectionMatrixLoader: std::exception thrown deleting database entries: \"";
00496                 errorString += er.what();
00497                 errorString += "\"";
00498                 showError(errorString);
00499         }
00500 }
00501 
00502 
00503 /*! Writes error message to std out and shows message box with error.
00504         NOTE Not thread safe.*/
00505 void ConnectionMatrixLoader::showError(const char* errMsg){
00506         cerr<<errMsg<<endl;
00507         QMessageBox::critical( 0, "Connection Matrix Loader Error", errMsg);
00508         errorState = true;
00509 }
00510 
00511 
00512 /*! Writes error message to std out and shows message box with error.
00513         NOTE Not thread safe.*/
00514 void ConnectionMatrixLoader::showError(const QString& errMsg){
00515         cerr<<errMsg<<endl;
00516         QMessageBox::critical( 0, "Connection Matrix Loader Error", errMsg);
00517         errorState = true;
00518 }
00519 

Generated on Mon Sep 3 22:29:04 2007 for SpikeStream Application by  doxygen 1.4.4