SpikeStream Library
0.2
|
00001 //SpikeStream includes 00002 #include "ConfigLoader.h" 00003 #include "Connection.h" 00004 #include "GlobalVariables.h" 00005 #include "NetworkDaoThread.h" 00006 #include "Neuron.h" 00007 #include "PerformanceTimer.h" 00008 #include "SpikeStreamException.h" 00009 #include "SpikeStreamDBException.h" 00010 #include "Util.h" 00011 using namespace spikestream; 00012 00013 #include <iostream> 00014 using namespace std; 00015 00017 #define TIME_PERFORMANCE 00018 00020 //#define DEBUG 00021 00022 00024 NetworkDaoThread::NetworkDaoThread(const DBInfo& dbInfo, const QString& name) : NetworkDao(dbInfo) { 00025 this->setObjectName(name); 00026 currentTask = NO_TASK_DEFINED; 00027 clearError(); 00028 stopThread = true; 00029 progressMessage = "Not running"; 00030 00031 //Load up configuration parameters 00032 ConfigLoader configLoader; 00033 numConBuffers = Util::getInt(configLoader.getParameter("number_insert_connection_buffers")); 00034 numNeurBuffers = Util::getInt(configLoader.getParameter("number_insert_neuron_buffers")); 00035 } 00036 00037 00039 NetworkDaoThread::~NetworkDaoThread(){ 00040 } 00041 00042 00043 /*----------------------------------------------------------*/ 00044 /*----- PUBLIC METHODS -----*/ 00045 /*----------------------------------------------------------*/ 00046 00048 void NetworkDaoThread::prepareAddConnectionGroup(unsigned int networkID, ConnectionGroup* connGrp){ 00049 //Copy connection group into a list and call the mai nconnection group adding method 00050 QList<ConnectionGroup*> tmpConGrpList; 00051 tmpConGrpList.append(connGrp); 00052 prepareAddConnectionGroups(networkID, tmpConGrpList); 00053 } 00054 00055 00057 void NetworkDaoThread::prepareAddConnectionGroups(unsigned int networkID, QList<ConnectionGroup*>& connGrpList){ 00058 //Store necessary variables 00059 this->networkID = networkID; 00060 this->connectionGroupList = connGrpList; 00061 00062 //Set the task that will run when the thread starts 00063 currentTask = ADD_CONNECTION_GROUPS_TASK; 00064 00065 //Record the total number of steps that the task involves 00066 totalNumberOfSteps = 1; 00067 } 00068 00069 00071 void NetworkDaoThread::prepareAddNeuronGroup(unsigned int networkID, NeuronGroup* neurGrp){ 00072 //Copy neuron group into a list and call the main method to add neuron groups 00073 QList<NeuronGroup*> tmpNeurGrpList; 00074 tmpNeurGrpList.append(neurGrp); 00075 prepareAddNeuronGroups(networkID, tmpNeurGrpList); 00076 } 00077 00078 00080 void NetworkDaoThread::prepareAddNeuronGroups(unsigned int networkID, QList<NeuronGroup*>& neurGrpList){ 00081 //Store necessary variables 00082 this->networkID = networkID; 00083 this->neuronGroupList = neurGrpList; 00084 00085 //Set the task that will run when the thread starts 00086 currentTask = ADD_NEURON_GROUPS_TASK; 00087 00088 //Record the total number of steps that the task involves 00089 totalNumberOfSteps = 1; 00090 } 00091 00092 00094 void NetworkDaoThread::prepareDeleteConnectionGroups(unsigned int networkID, QList<unsigned int>& conGrpList){ 00095 //Store necessary variables 00096 this->networkID = networkID; 00097 this->connectionGroupIDList = conGrpList; 00098 00099 //Set the task that will run when the thread starts 00100 currentTask = DELETE_CONNECTION_GROUPS_TASK; 00101 00102 //Record the total number of steps that the task involves 00103 totalNumberOfSteps = 1; 00104 progressMessage = "Deleting connection groups."; 00105 } 00106 00107 00109 void NetworkDaoThread::prepareDeleteNeuronGroups(unsigned int networkID, QList<unsigned int>& neurGrpList){ 00110 //Store necessary variables 00111 this->networkID = networkID; 00112 this->neuronGroupIDList = neurGrpList; 00113 00114 //Set the task that will run when the thread starts 00115 currentTask = DELETE_NEURON_GROUPS_TASK; 00116 00117 //Record the total number of steps that the task involves 00118 totalNumberOfSteps = 1; 00119 progressMessage = "Deleting neuron groups."; 00120 } 00121 00122 00124 void NetworkDaoThread::prepareLoadConnections(const QList<ConnectionGroup*>& connGrpList){ 00125 //Store necessary variables 00126 this->connectionGroupList = connGrpList; 00127 00128 //Set the taks that will run when the thread starts 00129 currentTask = LOAD_CONNECTIONS_TASK; 00130 progressMessage = "Loading connections"; 00131 } 00132 00133 00135 void NetworkDaoThread::prepareLoadConnections(ConnectionGroup* connGrp){ 00136 //Store necessary variables 00137 connectionGroupList.clear(); 00138 connectionGroupList.append(connGrp); 00139 00140 //Set the task that will run when the thread starts 00141 currentTask = LOAD_CONNECTIONS_TASK; 00142 progressMessage = "Loading connections"; 00143 } 00144 00145 00147 void NetworkDaoThread::prepareLoadNeurons(const QList<NeuronGroup*>& neurGrpList){ 00148 //Store necessary variables 00149 this->neuronGroupList = neurGrpList; 00150 00151 //Set the task that will run when the thread starts 00152 currentTask = LOAD_NEURONS_TASK; 00153 progressMessage = "Loading neurons"; 00154 } 00155 00156 00158 void NetworkDaoThread::prepareLoadNeurons(NeuronGroup* neurGrp){ 00159 //Store necessary variables 00160 neuronGroupList.clear(); 00161 neuronGroupList.append(neurGrp); 00162 00163 //Set the task that will run when the thread starts 00164 currentTask = LOAD_NEURONS_TASK; 00165 progressMessage = "Loading neurons"; 00166 } 00167 00168 00170 void NetworkDaoThread::clearError(){ 00171 errorMessage = ""; 00172 error = false; 00173 } 00174 00175 00178 void NetworkDaoThread::run(){ 00179 stopThread = false; 00180 clearError(); 00181 numberOfCompletedSteps = 0; 00182 try{ 00183 //Connect to the database now that we are in a separate thread 00184 connectToDatabase(); 00185 00186 switch(currentTask){ 00187 case ADD_NEURON_GROUPS_TASK: 00188 addNeuronGroups(); 00189 break; 00190 case ADD_CONNECTION_GROUPS_TASK: 00191 addConnectionGroups(); 00192 break; 00193 case DELETE_CONNECTION_GROUPS_TASK: 00194 deleteConnectionGroups(); 00195 break; 00196 case DELETE_NETWORK_TASK: 00197 deleteConnectionGroups(); 00198 deleteNeuronGroups(); 00199 deleteNetwork(); 00200 break; 00201 case DELETE_NEURON_GROUPS_TASK: 00202 deleteNeuronGroups(); 00203 break; 00204 case LOAD_CONNECTIONS_TASK: 00205 loadConnections(); 00206 break; 00207 case LOAD_NEURONS_TASK: 00208 loadNeurons(); 00209 break; 00210 case SAVE_NETWORK_TASK: 00211 saveNetwork(); 00212 break; 00213 case SAVE_TEMP_WEIGHTS_TASK: 00214 saveTempWeights(); 00215 break; 00216 default: 00217 setError("NetworkDaoThread started without defined task."); 00218 } 00219 00220 //Database connection can be closed 00221 closeDatabaseConnection(); 00222 } 00223 catch(SpikeStreamException& ex){ 00224 setError("NetworkDaoThread: SpikeStreamException thrown carrying out current task: " + ex.getMessage()); 00225 } 00226 catch(...){ 00227 setError("Unrecognized exception thrown carrying out current task."); 00228 } 00229 00230 //Current task is complete 00231 neuronGroupIDList.clear(); 00232 neuronGroupList.clear(); 00233 connectionGroupIDList.clear(); 00234 connectionGroupList.clear(); 00235 networkID = 0; 00236 currentTask = NO_TASK_DEFINED; 00237 stopThread = true; 00238 } 00239 00240 00242 void NetworkDaoThread::startDeleteNetwork(unsigned networkID){ 00243 this->networkID = networkID; 00244 //Store list of connection group IDs 00245 connectionGroupIDList.clear(); 00246 QList<ConnectionGroupInfo> conGrpInfoList; 00247 getConnectionGroupsInfo(networkID, conGrpInfoList); 00248 foreach(ConnectionGroupInfo conGrpInfo, conGrpInfoList) 00249 connectionGroupIDList.append(conGrpInfo.getID()); 00250 00251 //Store list of neuron group IDs 00252 neuronGroupIDList.clear(); 00253 QList<NeuronGroupInfo> neurGrpInfoList; 00254 getNeuronGroupsInfo(networkID, neurGrpInfoList); 00255 foreach(NeuronGroupInfo neurGrpInfo, neurGrpInfoList) 00256 neuronGroupIDList.append(neurGrpInfo.getID()); 00257 00258 //Prepare and start task 00259 currentTask = DELETE_NETWORK_TASK; 00260 progressMessage = "Deleting network"; 00261 start(); 00262 } 00263 00264 00266 void NetworkDaoThread::startSaveNetwork(unsigned networkID, QList<NeuronGroup*> newNeuronGroups, QList<ConnectionGroup*> newConnectionGroups, QList<unsigned> deleteNeuronGroupIDs, QList<unsigned> deleteConnectionGroupIDs, QList<ConnectionGroup*> volatileConnectionGroups){ 00267 //Store data 00268 this->networkID = networkID; 00269 this->neuronGroupList = newNeuronGroups; 00270 this->connectionGroupList = newConnectionGroups; 00271 this->neuronGroupIDList = deleteNeuronGroupIDs; 00272 this->connectionGroupIDList = deleteConnectionGroupIDs; 00273 this->volatileConnectionGroupList = volatileConnectionGroups; 00274 00275 //Start thread running 00276 currentTask = SAVE_NETWORK_TASK; 00277 progressMessage = "Saving network"; 00278 start(); 00279 } 00280 00281 00283 void NetworkDaoThread::startSaveTempWeights(QList<ConnectionGroup*>& connectionGroupList){ 00284 //Store data 00285 this->volatileConnectionGroupList = connectionGroupList; 00286 00287 //Start thread running 00288 currentTask = SAVE_TEMP_WEIGHTS_TASK; 00289 numberOfCompletedSteps = 0; 00290 totalNumberOfSteps = 0; 00291 progressMessage = "Saving temporary weights"; 00292 start(); 00293 } 00294 00295 00297 void NetworkDaoThread::stop(){ 00298 stopThread = true; 00299 } 00300 00301 00302 /*----------------------------------------------------------*/ 00303 /*----- PRIVATE METHODS -----*/ 00304 /*----------------------------------------------------------*/ 00305 00309 void NetworkDaoThread::addConnectionGroups(){ 00310 //Reset progress measure 00311 numberOfCompletedSteps = 0; 00312 totalNumberOfSteps = connectionGroupList.size(); 00313 progressMessage = "Adding Connections"; 00314 00315 //Work through the list of connection groups 00316 for(QList<ConnectionGroup*>::iterator iter = connectionGroupList.begin(); iter != connectionGroupList.end() && !stopThread; ++iter){ 00317 //Get a pointer to the connection group 00318 ConnectionGroup* connectionGroup = *iter; 00319 00320 //Get a copy of the information about the connection group 00321 ConnectionGroupInfo connGrpInfo = connectionGroup->getInfo(); 00322 00323 //Build query string 00324 QString queryStr = "INSERT INTO ConnectionGroups (NetworkID, Description, FromNeuronGroupID, ToNeuronGroupID, Parameters, SynapseTypeID ) VALUES ("; 00325 queryStr += QString::number(networkID) + ", "; 00326 queryStr += "'" + connGrpInfo.getDescription() + "', "; 00327 queryStr += QString::number(connGrpInfo.getFromNeuronGroupID()) + ", "; 00328 queryStr += QString::number(connGrpInfo.getToNeuronGroupID()) + ", "; 00329 queryStr += "'" + connGrpInfo.getParameterXML() + "', "; 00330 queryStr += QString::number(connGrpInfo.getSynapseTypeID()) + ")"; 00331 QSqlQuery query = getQuery(queryStr); 00332 executeQuery(query); 00333 00334 //Check id is correct and add to connection group info if it is 00335 int lastInsertID = query.lastInsertId().toInt(); 00336 if(lastInsertID >= START_CONNECTIONGROUP_ID) 00337 connectionGroup->setID(lastInsertID); 00338 else{ 00339 throw SpikeStreamException("Insert ID for ConnectionGroup is invalid."); 00340 } 00341 00342 //Add entry for connection group parameters 00343 //Get name of table 00344 SynapseType synapseType = getSynapseType(connGrpInfo.getSynapseTypeID()); 00345 00346 //Add parameter table entry for this connection group 00347 executeQuery( "INSERT INTO " + synapseType.getParameterTableName() + "(ConnectionGroupID) VALUES (" + QString::number(connectionGroup->getID()) + ")" ); 00348 00349 //Set synapse parameters to default values if they have not been set 00350 if(!connectionGroup->parametersSet()){ 00351 QHash<QString, double> tmpParamMap = getDefaultSynapseParameters(connectionGroup->getSynapseTypeID()); 00352 connectionGroup->setParameters(tmpParamMap); 00353 } 00354 00355 //Copy parameters from connection group into parameter table 00356 QHash<QString, double> tmpParamMap = connectionGroup->getParameters(); 00357 setSynapseParameters(connectionGroup->getInfo(), tmpParamMap); 00358 00359 #ifdef TIME_PERFORMANCE 00360 PerformanceTimer timer; 00361 #endif//TIME_PERFORMANCE 00362 00363 //Build query 00364 query = getQuery(); 00365 queryStr = "INSERT INTO Connections ( ConnectionGroupID, FromNeuronID, ToNeuronID, Delay, Weight) VALUES "; 00366 for(int i=0; i<numConBuffers-1; ++i) 00367 queryStr += "(?, ?, ?, ?, ?),"; 00368 queryStr += "(?, ?, ?, ?, ?)"; 00369 query.prepare(queryStr); 00370 00371 //Add connections to database 00372 int conCntr = 0, offset = 0, conAddedCntr = 0; 00373 QList<Connection*> tmpConList; 00374 ConnectionIterator endConGrp = connectionGroup->end(); 00375 for(ConnectionIterator iter = connectionGroup->begin(); iter != endConGrp && !stopThread; ++iter){ 00376 offset = 5 * (conCntr % numConBuffers); 00377 00378 //Bind values to query 00379 tmpConList.append(&(*iter)); 00380 query.bindValue(0 + offset, connectionGroup->getID()); 00381 query.bindValue(1 + offset, iter->getFromNeuronID()); 00382 query.bindValue(2 + offset, iter->getToNeuronID()); 00383 query.bindValue(3 + offset, iter->getDelay()); 00384 query.bindValue(4 + offset, iter->getWeight()); 00385 00386 //Execute query 00387 if(conCntr % numConBuffers == numConBuffers-1){ 00388 executeQuery(query); 00389 00390 //Add connection id to connection - last insert id is the id of the first connection in the list of value entries 00391 int lastInsertID = query.lastInsertId().toInt(); 00392 if( (lastInsertID + tmpConList.size()) > LAST_CONNECTION_ID ) 00393 throw SpikeStreamException("Database generated connection ID is out of range: " + QString::number(lastInsertID + tmpConList.size()) + ". It must be less than or equal to " + QString::number(LAST_CONNECTION_ID)); 00394 if(lastInsertID < START_CONNECTION_ID) 00395 throw SpikeStreamException("Insert ID for Connection is invalid."); 00396 if(tmpConList.size() != numConBuffers) 00397 throw SpikeStreamException("Temporary connection list size " + QString::number(tmpConList.size()) + " does not match number of buffers: " + QString::number(numConBuffers)); 00398 00399 //Set connection ID in connection groups 00400 for(int i=0; i<tmpConList.size(); ++i){ 00401 tmpConList.at(i)->setID(lastInsertID + i); 00402 } 00403 00404 //Count number of connections that have been added 00405 conAddedCntr += numConBuffers; 00406 00407 //Clear up list 00408 tmpConList.clear(); 00409 } 00410 00411 //Keep track of the number of connections 00412 ++conCntr; 00413 } 00414 00415 //Add remaining connections individually 00416 if(!tmpConList.isEmpty() && !stopThread){ 00417 query = getQuery(); 00418 query.prepare("INSERT INTO Connections ( ConnectionGroupID, FromNeuronID, ToNeuronID, Delay, Weight) VALUES (?, ?, ?, ?, ?)"); 00419 for(QList<Connection*>::iterator iter = tmpConList.begin(); iter != tmpConList.end(); ++iter){ 00420 query.bindValue(0, connectionGroup->getID()); 00421 query.bindValue(1, (*iter)->getFromNeuronID()); 00422 query.bindValue(2, (*iter)->getToNeuronID()); 00423 query.bindValue(3, (*iter)->getDelay()); 00424 query.bindValue(4, (*iter)->getWeight()); 00425 00426 //Execute query 00427 executeQuery(query); 00428 00429 //Add connection id to connection 00430 int lastInsertID = query.lastInsertId().toInt(); 00431 if( lastInsertID > LAST_CONNECTION_ID ) 00432 throw SpikeStreamException("Database generated connection ID is out of range: " + QString::number(lastInsertID) + ". It must be less than or equal to " + QString::number(LAST_CONNECTION_ID)); 00433 if(lastInsertID < START_CONNECTION_ID) 00434 throw SpikeStreamException("Insert ID for Connection is invalid."); 00435 (*iter)->setID(lastInsertID); 00436 00437 //Count number of connections that have been added 00438 ++conAddedCntr; 00439 } 00440 } 00441 00442 //Check that we have added all the connections 00443 if(!stopThread && (connectionGroup->size() != conAddedCntr) ) 00444 throw SpikeStreamException("Number of connections added to database: " + QString::number(conAddedCntr) + " does not match size of connection group: " + QString::number(connectionGroup->size())); 00445 00446 //Update progress 00447 ++numberOfCompletedSteps; 00448 00449 #ifdef TIME_PERFORMANCE 00450 timer.printTime("Number of buffers: " + QString::number(numConBuffers) + ". Number of connections remaining: " + QString::number(tmpConList.size()) + ". Adding " + QString::number(conCntr) + " connections"); 00451 #endif//TIME_PERFORMANCE 00452 } 00453 00454 //Clean up connection groups if task was cancelled. 00455 if(stopThread){ 00456 connectionGroupIDList.clear(); 00457 foreach(ConnectionGroup* conGrp, connectionGroupList) 00458 connectionGroupIDList.append(conGrp->getID()); 00459 deleteConnectionGroups(); 00460 } 00461 } 00462 00463 00466 void NetworkDaoThread::addNeuronGroups(){ 00467 //Reset progress measure 00468 numberOfCompletedSteps = 0; 00469 totalNumberOfSteps = neuronGroupList.size(); 00470 progressMessage = "Adding Neurons"; 00471 00472 //Check that parameters have been set correctly 00473 if(networkID == 0){ 00474 setError("Network ID has not been set."); 00475 return; 00476 } 00477 //Work through the list of neuron groups 00478 for(QList<NeuronGroup*>::iterator neurGrpIter = neuronGroupList.begin(); neurGrpIter != neuronGroupList.end() && !stopThread; ++neurGrpIter){ 00479 //User friendly pointer to group 00480 NeuronGroup* neuronGroup = *neurGrpIter; 00481 00482 //Get information about the neuron group 00483 NeuronGroupInfo neurGrpInfo = neuronGroup->getInfo(); 00484 00485 //Add the neuron group first 00486 QString queryStr = "INSERT INTO NeuronGroups (NetworkID, Name, Description, Parameters, NeuronTypeID ) VALUES ("; 00487 queryStr += QString::number(networkID) + ", "; 00488 queryStr += "'" + neurGrpInfo.getName() + "', '" + neurGrpInfo.getDescription() + "', '" + neurGrpInfo.getParameterXML() + "', "; 00489 queryStr += QString::number(neurGrpInfo.getNeuronTypeID()) + ")"; 00490 QSqlQuery query = getQuery(queryStr); 00491 executeQuery(query); 00492 00493 //Check id is correct and add to neuron group info if it is 00494 int lastInsertID = query.lastInsertId().toInt(); 00495 if(lastInsertID >= START_NEURONGROUP_ID) 00496 neuronGroup->setID(lastInsertID);//Set this on neuron group, not on the copied info 00497 else{ 00498 setError("Insert ID for NeuronGroup is invalid."); 00499 return; 00500 } 00501 00502 //Add entry for neuron group parameters 00503 //Get name of table 00504 NeuronType neurType = getNeuronType(neurGrpInfo.getNeuronTypeID()); 00505 00506 //Add parameter table entry for this neuron group 00507 executeQuery( "INSERT INTO " + neurType.getParameterTableName() + "(NeuronGroupID) VALUES (" + QString::number(neuronGroup->getID()) + ")" ); 00508 00509 //Check neuron group has parameters set and add default parameters if not 00510 if(!neuronGroup->parametersSet()){ 00511 QHash<QString, double> tmpParamMap = getDefaultNeuronParameters(neuronGroup->getNeuronTypeID()); 00512 neuronGroup->setParameters(tmpParamMap); 00513 } 00514 00515 //Copy parameters from neuron group into parameter table 00516 QHash<QString, double> tmpParamMap = neuronGroup->getParameters(); 00517 setNeuronParameters(neuronGroup->getInfo(), tmpParamMap); 00518 00519 #ifdef TIME_PERFORMANCE 00520 PerformanceTimer timer; 00521 #endif//TIME_PERFORMANCE 00522 00523 //Build query 00524 query = getQuery(); 00525 queryStr = "INSERT INTO Neurons (NeuronGroupID, X, Y, Z) VALUES "; 00526 for(int i=0; i<numNeurBuffers-1; ++i) 00527 queryStr += "(?, ?, ?, ?),"; 00528 queryStr += "(?, ?, ?, ?)"; 00529 query.prepare(queryStr); 00530 00531 //Add neurons to database 00532 int neurCntr = 0, offset = 0, neurAddedCntr = 0, tmpNeurGrpID = neuronGroup->getID(); 00533 NeuronMap* newNeurMap = new NeuronMap(); 00534 QList<Neuron*> tmpNeurList; 00535 NeuronIterator endNeurGrp = neuronGroup->end(); 00536 for(NeuronIterator neurIter = neuronGroup->begin(); neurIter != endNeurGrp && !stopThread; ++neurIter){ 00537 offset = 4 * (neurCntr % numNeurBuffers); 00538 00539 //Bind values to query 00540 tmpNeurList.append(neurIter.value()); 00541 query.bindValue(0 + offset, tmpNeurGrpID); 00542 query.bindValue(1 + offset, neurIter.value()->getXPos()); 00543 query.bindValue(2 + offset, neurIter.value()->getYPos()); 00544 query.bindValue(3 + offset, neurIter.value()->getZPos()); 00545 00546 //Execute query if we have added a whole number of buffers 00547 if(neurCntr % numNeurBuffers == numNeurBuffers-1){ 00548 executeQuery(query); 00549 00550 //Add neuron id to neuron - last insert id is the id of the first neuron in the list of value entries 00551 int lastInsertID = query.lastInsertId().toInt(); 00552 if( (lastInsertID + tmpNeurList.size()) > LAST_NEURON_ID ) 00553 throw SpikeStreamException("Database generated neuron ID is out of range: " + QString::number(lastInsertID + tmpNeurList.size()) + ". It must be less than or equal to " + QString::number(LAST_NEURON_ID)); 00554 if(lastInsertID < START_NEURON_ID) 00555 throw SpikeStreamException("Insert ID for Neuron is invalid."); 00556 if(tmpNeurList.size() != numNeurBuffers) 00557 throw SpikeStreamException("Temporary neuron list size " + QString::number(tmpNeurList.size()) + " does not match number of buffers: " + QString::number(numNeurBuffers)); 00558 00559 //Set neuron IDs and add neurons to new map with the new ID 00560 for(int i=0; i<tmpNeurList.size(); ++i){ 00561 tmpNeurList.at(i)->setID(lastInsertID + i); 00562 (*newNeurMap)[lastInsertID + i] = tmpNeurList.at(i); 00563 } 00564 00565 //Count number of neurons that have been added 00566 neurAddedCntr += numNeurBuffers; 00567 00568 //Clear up list 00569 tmpNeurList.clear(); 00570 } 00571 00572 //Keep track of the number of neurons 00573 ++neurCntr; 00574 } 00575 00576 //Add remaining neurons individually 00577 if(!tmpNeurList.isEmpty()){ 00578 query = getQuery(); 00579 query.prepare("INSERT INTO Neurons ( NeuronGroupID, X, Y, Z) VALUES (?, ?, ?, ?)"); 00580 for(QList<Neuron*>::iterator neurListIter = tmpNeurList.begin(); neurListIter != tmpNeurList.end(); ++neurListIter){ 00581 query.bindValue(0, tmpNeurGrpID); 00582 query.bindValue(1, (*neurListIter)->getXPos()); 00583 query.bindValue(2, (*neurListIter)->getYPos()); 00584 query.bindValue(3, (*neurListIter)->getZPos()); 00585 00586 //Execute query 00587 executeQuery(query); 00588 00589 //Add neuron id to neuron 00590 int lastInsertID = query.lastInsertId().toInt(); 00591 if( (lastInsertID) > LAST_NEURON_ID ) 00592 throw SpikeStreamException("Database generated neuron ID is out of range: " + QString::number(lastInsertID) + ". It must be less than or equal to " + QString::number(LAST_NEURON_ID)); 00593 if(lastInsertID < START_NEURON_ID) 00594 throw SpikeStreamException("Insert ID for Neuron is invalid."); 00595 (*neurListIter)->setID(lastInsertID); 00596 (*newNeurMap)[lastInsertID] = *neurListIter; 00597 00598 //Count number of neurons that have been added 00599 ++neurAddedCntr; 00600 } 00601 } 00602 00603 //Check that we have added all the neurons 00604 if(!stopThread && (neuronGroup->size() != neurAddedCntr)) 00605 throw SpikeStreamException("Number of neurons added to database: " + QString::number(neurAddedCntr) + " does not match size of neuron group: " + QString::number(neuronGroup->size())); 00606 00607 //Set the start ID of the neuron group 00608 NetworkDao networkDao(this->getDBInfo()); 00609 neuronGroup->setStartNeuronID( networkDao.getStartNeuronID(tmpNeurGrpID) ); 00610 00611 #ifdef TIME_PERFORMANCE 00612 timer.printTime("Adding neurons. Number of buffers: " + QString::number(numNeurBuffers) + ". Number of neurons remaining: " + QString::number(tmpNeurList.size()) + ". Added " + QString::number(neurAddedCntr) + " neurons"); 00613 #endif//TIME_PERFORMANCE 00614 00615 //Add the new map to the neuron group. This should also clean up the old map 00616 neuronGroup->setNeuronMap(newNeurMap); 00617 00618 //Track progress 00619 ++numberOfCompletedSteps; 00620 } 00621 00622 //Clean up neuron groups if task was cancelled. 00623 if(stopThread){ 00624 neuronGroupIDList.clear(); 00625 foreach(NeuronGroup* neurGrp, neuronGroupList) 00626 neuronGroupIDList.append(neurGrp->getID()); 00627 deleteNeuronGroups(); 00628 } 00629 } 00630 00631 00633 void NetworkDaoThread::deleteConnectionGroups(){ 00634 numberOfCompletedSteps = 0; 00635 totalNumberOfSteps = connectionGroupIDList.size(); 00636 progressMessage = "Deleting connection groups"; 00637 00638 //Check that network ID is valid 00639 if(networkID == 0){ 00640 setError("Network ID has not been set."); 00641 return; 00642 } 00643 00644 //Work through the list of connection groups 00645 foreach(unsigned int conGroupID, connectionGroupIDList){ 00646 executeQuery("DELETE FROM Connections WHERE ConnectionGroupID=" + QString::number(conGroupID) ); 00647 executeQuery("DELETE FROM ConnectionGroups WHERE NetworkID="+ QString::number(networkID) + " AND ConnectionGroupID=" + QString::number(conGroupID) ); 00648 ++numberOfCompletedSteps; 00649 } 00650 00651 //Reset list 00652 connectionGroupIDList.clear(); 00653 } 00654 00655 00658 void NetworkDaoThread::deleteNetwork(){ 00659 numberOfCompletedSteps = 0; 00660 totalNumberOfSteps = 1; 00661 progressMessage = "Deleting network."; 00662 executeQuery("DELETE FROM Networks WHERE NetworkID = " + QString::number(networkID)); 00663 networkID = 0; 00664 numberOfCompletedSteps = 1; 00665 } 00666 00667 00669 void NetworkDaoThread::deleteNeuronGroups(){ 00670 numberOfCompletedSteps = 0; 00671 totalNumberOfSteps = neuronGroupIDList.size(); 00672 progressMessage = "Deleting neuron groups"; 00673 00674 //Check that network id is valid 00675 if(networkID == 0){ 00676 setError("Network ID has not been set."); 00677 return; 00678 } 00679 00680 //Work through the list of neuron groups 00681 foreach(unsigned int neuronGroupID, neuronGroupIDList){ 00682 executeQuery("DELETE FROM Neurons WHERE NeuronGroupID=" + QString::number(neuronGroupID) ); 00683 executeQuery("DELETE FROM NeuronGroups WHERE NetworkID="+ QString::number(networkID) + " AND NeuronGroupID=" + QString::number(neuronGroupID) ); 00684 ++numberOfCompletedSteps; 00685 } 00686 00687 //Reset list 00688 neuronGroupIDList.clear(); 00689 } 00690 00691 00693 void NetworkDaoThread::loadConnections(){ 00694 //Reset progress 00695 numberOfCompletedSteps = 0; 00696 totalNumberOfSteps = getConnectionCount(connectionGroupList); 00697 00698 //Work through all the connections to be loaded 00699 for(QList<ConnectionGroup*>::iterator iter = connectionGroupList.begin(); iter != connectionGroupList.end(); ++iter){ 00700 00701 //Empty current connections in group 00702 (*iter)->clearConnections(); 00703 00704 //Load connections into group 00705 unsigned int tmpConGrpID = (*iter)->getID(); 00706 QSqlQuery query = getQuery("SELECT ConnectionID, FromNeuronID, ToNeuronID, Delay, Weight FROM Connections WHERE ConnectionGroupID = " + QString::number(tmpConGrpID)); 00707 executeQuery(query); 00708 while ( query.next() ) { 00709 (*iter)->addConnection( 00710 query.value(0).toUInt(),//ID 00711 query.value(1).toUInt(),//FromNeuronID 00712 query.value(2).toUInt(),//ToNeuronID 00713 query.value(3).toString().toFloat(),//Delay 00714 query.value(4).toString().toFloat()//Weight 00715 ); 00716 00717 //Track progress 00718 ++numberOfCompletedSteps; 00719 00720 //Quit if user cancels 00721 if(stopThread) 00722 return; 00723 } 00724 00725 //Load parameters in connection group 00726 QHash<QString, double> tmpParamMap = getSynapseParameters( (*iter)->getInfo()); 00727 (*iter)->setParameters(tmpParamMap); 00728 } 00729 } 00730 00731 00733 void NetworkDaoThread::loadNeurons(){ 00734 //Reset progress measure 00735 numberOfCompletedSteps = 0; 00736 totalNumberOfSteps = getNeuronCount(neuronGroupList); 00737 00738 //Work through all the neurons to be loaded 00739 for(QList<NeuronGroup*>::iterator iter = neuronGroupList.begin(); iter != neuronGroupList.end(); ++iter){ 00740 00741 //Empty current connections in group 00742 (*iter)->clearNeurons(); 00743 00744 //Get pointer to neuron map 00745 NeuronMap* tmpNeurMap = (*iter)->getNeuronMap(); 00746 00747 //Load neurons into group 00748 bool firstTime = true; 00749 QSqlQuery query = getQuery("SELECT NeuronID, X, Y, Z FROM Neurons WHERE NeuronGroupID = " + QString::number((*iter)->getID()) + " ORDER BY NeuronID"); 00750 executeQuery(query); 00751 while ( query.next() ) { 00752 Neuron* tmpNeuron = new Neuron( 00753 query.value(0).toUInt(),//ID 00754 query.value(1).toString().toFloat(),//X 00755 query.value(2).toString().toFloat(),//Y 00756 query.value(3).toString().toFloat()//Z 00757 ); 00758 (*tmpNeurMap)[query.value(0).toUInt()] = tmpNeuron; 00759 00760 //Store the start neuron id - useful when neurons are stored continuously, which is usually but not always the case 00761 if(firstTime){ 00762 (*iter)->setStartNeuronID(query.value(0).toUInt()); 00763 firstTime = false; 00764 } 00765 00766 //Track progress 00767 ++numberOfCompletedSteps; 00768 00769 //Quit if user cancels 00770 if(stopThread) 00771 return; 00772 } 00773 00774 //Load parameters in neuron group 00775 QHash<QString, double> tmpParamMap = getNeuronParameters( (*iter)->getInfo()); 00776 (*iter)->setParameters(tmpParamMap); 00777 } 00778 } 00779 00780 00784 void NetworkDaoThread::setError(const QString& msg){ 00785 errorMessage = msg; 00786 error = true; 00787 stopThread = true; 00788 } 00789 00790 00792 void NetworkDaoThread::saveNetwork(){ 00793 #ifdef DEBUG 00794 cout<<"Saving network."<<endl; 00795 if(!neuronGroupIDList.isEmpty()){ 00796 cout<<"Deleting neuron groups with IDs: "; 00797 foreach(unsigned int neuronGroupID, neuronGroupIDList){ 00798 cout<<neuronGroupID<<" "; 00799 } 00800 cout<<endl; 00801 } 00802 if(!connectionGroupIDList.isEmpty()){ 00803 cout<<"Deleting connection groups with IDs: "; 00804 foreach(unsigned int neuronGroupID, connectionGroupIDList){ 00805 cout<<neuronGroupID<<" "; 00806 } 00807 cout<<endl; 00808 } 00809 if(!neuronGroupList.isEmpty()){ 00810 cout<<"Adding neuron groups with temporary IDs: "; 00811 foreach(NeuronGroup* neuronGroup, neuronGroupList){ 00812 cout<<neuronGroup->getID()<<" "; 00813 } 00814 cout<<endl; 00815 } 00816 if(!connectionGroupList.isEmpty()){ 00817 cout<<"Adding connection groups with temporary IDs: "; 00818 foreach(ConnectionGroup* conGroup, connectionGroupList){ 00819 cout<<conGroup->getID()<<" "; 00820 } 00821 cout<<endl; 00822 } 00823 #endif//DEBUG 00824 00825 progressMessage = "Saving network"; 00826 00827 //Delete neuron and connection groups that have been deleted from the prototype 00828 deleteNeuronGroups(); 00829 deleteConnectionGroups(); 00830 00831 /* Store link between old IDs and neurons in the groups that we are going to add. 00832 Also store link between old neuron group IDs and neuron group IDs */ 00833 QHash<unsigned, Neuron*> oldIDNeurMap; 00834 QHash<unsigned, NeuronGroup*> oldIDNeurGrpMap; 00835 foreach(NeuronGroup* tmpNeurGrp, neuronGroupList){ 00836 //Store old neuron group ID 00837 oldIDNeurGrpMap[tmpNeurGrp->getID()] = tmpNeurGrp; 00838 00839 //Store old neuron IDS 00840 QHash<unsigned, Neuron*>::iterator endNeurGrp = tmpNeurGrp->end(); 00841 for(QHash<unsigned, Neuron*>::iterator neurIter = tmpNeurGrp->begin(); neurIter != endNeurGrp; ++neurIter){ 00842 oldIDNeurMap[neurIter.key()] = neurIter.value(); 00843 } 00844 } 00845 00846 //Add neuron groups to database, the new IDs wil be stored in the neurons and neuron groups 00847 addNeuronGroups(); 00848 00849 //Update connections with the new IDs 00850 foreach(ConnectionGroup* tmpConGrp, connectionGroupList){ 00851 //Update FROM neuron group ID and FROM neuron IDs 00852 if(oldIDNeurGrpMap.contains(tmpConGrp->getFromNeuronGroupID())){ 00853 tmpConGrp->setFromNeuronGroupID(oldIDNeurGrpMap[tmpConGrp->getFromNeuronGroupID()]->getID()); 00854 ConnectionIterator endConGrp = tmpConGrp->end(); 00855 for(ConnectionIterator conIter = tmpConGrp->begin(); conIter!= endConGrp; ++conIter){ 00856 //Check FROM neuron ID exists 00857 if(oldIDNeurMap.contains(conIter->getFromNeuronID())) 00858 conIter->setFromNeuronID(oldIDNeurMap[conIter->getFromNeuronID()]->getID()); 00859 else 00860 throw SpikeStreamException("FROM neuron ID missing from old ID neuron map: " + QString::number(conIter->getFromNeuronID())); 00861 } 00862 } 00863 //Update TO neuron group ID and TO neuron IDs 00864 if(oldIDNeurGrpMap.contains(tmpConGrp->getToNeuronGroupID())){ 00865 tmpConGrp->setToNeuronGroupID(oldIDNeurGrpMap[tmpConGrp->getToNeuronGroupID()]->getID()); 00866 ConnectionIterator endConGrp = tmpConGrp->end(); 00867 for(ConnectionIterator conIter = tmpConGrp->begin(); conIter!= endConGrp; ++conIter){ 00868 //Check TO neuron ID exists 00869 if(oldIDNeurMap.contains(conIter->getToNeuronID())) 00870 conIter->setToNeuronID(oldIDNeurMap[conIter->getToNeuronID()]->getID()); 00871 else 00872 throw SpikeStreamException("TO neuron ID missing from old ID neuron map: " + QString::number(conIter->getToNeuronID())); 00873 } 00874 } 00875 } 00876 00877 //Add connection groups to the database, the new IDs will be stored in the connection groups 00878 addConnectionGroups(); 00879 00880 //Store volatile connection groups 00881 saveTempWeights(); 00882 } 00883 00884 00886 void NetworkDaoThread::saveTempWeights(){ 00887 //Reset progress measure 00888 numberOfCompletedSteps = 0; 00889 progressMessage = "Saving temporary weights"; 00890 00891 //Calculate number of steps 00892 for(QList<ConnectionGroup*>::iterator conGrpIter = volatileConnectionGroupList.begin(); conGrpIter != volatileConnectionGroupList.end() && !stopThread; ++conGrpIter) 00893 totalNumberOfSteps += (*conGrpIter)->size(); 00894 00895 //Work through the list of connection groups 00896 for(QList<ConnectionGroup*>::iterator conGrpIter = volatileConnectionGroupList.begin(); conGrpIter != volatileConnectionGroupList.end() && !stopThread; ++conGrpIter){ 00897 //Get a pointer to the connection group 00898 ConnectionGroup* tmpConGrp = *conGrpIter; 00899 00900 #ifdef TIME_PERFORMANCE 00901 PerformanceTimer timer; 00902 #endif//TIME_PERFORMANCE 00903 00904 //Build query 00905 QSqlQuery query = getQuery(); 00906 QString queryStr; 00907 for(int i=0; i<numConBuffers; ++i) 00908 queryStr += "UPDATE Connections SET Weight= ? WHERE ConnectionID = ?;"; 00909 query.prepare(queryStr); 00910 00911 //Work through the connections 00912 int conCntr = 0, offset = 0, conAddedCntr = 0; 00913 QList<Connection*> tmpConList; 00914 ConnectionIterator endConGrp = tmpConGrp->end(); 00915 for(ConnectionIterator conIter = tmpConGrp->begin(); conIter != endConGrp && !stopThread; ++conIter){ 00916 offset = 2 * (conCntr % numConBuffers); 00917 00918 //Bind values to query 00919 tmpConList.append(&(*conIter)); 00920 query.bindValue(0 + offset, conIter->getTempWeight()); 00921 query.bindValue(1 + offset, conIter->getID()); 00922 00923 //Execute query 00924 if(conCntr % numConBuffers == numConBuffers-1){ 00925 executeQuery(query); 00926 00927 //Count number of connections that have been added 00928 conAddedCntr += numConBuffers; 00929 numberOfCompletedSteps = conAddedCntr; 00930 00931 //Clear up list 00932 tmpConList.clear(); 00933 } 00934 00935 //Keep track of the number of connections 00936 ++conCntr; 00937 } 00938 00939 //Add remaining connections individually 00940 if(!tmpConList.isEmpty() && !stopThread){ 00941 query = getQuery(); 00942 query.prepare("UPDATE Connections SET Weight= ? WHERE ConnectionID = ?"); 00943 for(QList<Connection*>::iterator conIter = tmpConList.begin(); conIter != tmpConList.end(); ++conIter){ 00944 query.bindValue(0, (*conIter)->getTempWeight()); 00945 query.bindValue(1, (*conIter)->getID()); 00946 00947 //Execute query 00948 executeQuery(query); 00949 00950 //Count number of connections that have been added 00951 ++conAddedCntr; 00952 numberOfCompletedSteps = conAddedCntr; 00953 } 00954 } 00955 00956 //Check that we have added all the connections 00957 if(!stopThread && (tmpConGrp->size() != conAddedCntr) ) 00958 throw SpikeStreamException("Number of connections added to database: " + QString::number(conAddedCntr) + " does not match size of connection group: " + QString::number(tmpConGrp->size())); 00959 00960 #ifdef TIME_PERFORMANCE 00961 timer.printTime("Number of buffers: " + QString::number(numConBuffers) + ". Number of connections remaining: " + QString::number(tmpConList.size()) + ". Adding " + QString::number(conCntr) + " connections"); 00962 #endif//TIME_PERFORMANCE 00963 } 00964 00965 //Clean up 00966 volatileConnectionGroupList.clear(); 00967 } 00968