diff --git a/brian2genn/b2glib/convert_synapses.h b/brian2genn/b2glib/convert_synapses.h index 3bc1cc16..d7953b92 100644 --- a/brian2genn/b2glib/convert_synapses.h +++ b/brian2genn/b2glib/convert_synapses.h @@ -14,19 +14,29 @@ void convert_dynamic_arrays_2_dense_matrix(vector &source, vector &source, vector > bypreG; static unsigned int size; if (mode == b2g::FULL_MONTY) { - assert(source.size() == target.size()); - assert(source.size() == gvector.size()); - bypre.clear(); - bypre.resize(srcNN); - bypreG.clear(); - bypreG.resize(srcNN); - size= source.size(); - for (int i= 0; i < size; i++) { - assert(source[i] < srcNN); - assert(target[i] < trgNN); - bypre[source[i]].push_back(target[i]); - bypreG[source[i]].push_back(gvector[i]); - } - // convert this intermediate representation into the sparse synapses struct - // assume it has been allocated properly - unsigned int cnt= 0; - for (int i= 0; i < srcNN; i++) { - size= bypre[i].size(); - c.indInG[i]= cnt; - for (int j= 0; j < size; j++) { - c.ind[cnt]= bypre[i][j]; - gv[cnt]= bypreG[i][j]; + assert(source.size() == target.size()); + assert(source.size() == gvector.size()); + bypre.clear(); + bypre.resize(srcNN); + bypreG.clear(); + bypreG.resize(srcNN); + size= source.size(); + for (int i= 0; i < size; i++) { + assert(source[i] < srcNN); + assert(target[i] < trgNN); + bypre[source[i]].push_back(target[i]); + bypreG[source[i]].push_back(gvector[i]); + } + // convert this intermediate representation into the sparse synapses struct + // assume it has been allocated properly + unsigned int cnt= 0; + for (int i= 0; i < srcNN; i++) { + size= bypre[i].size(); + c.indInG[i]= cnt; + for (int j= 0; j < size; j++) { + c.ind[cnt]= bypre[i][j]; + gv[cnt]= bypreG[i][j]; // os << i << " " << c.ind[cnt] << " " << gv[cnt] << endl; - cnt++; - } - } - c.indInG[srcNN]= cnt; + cnt++; + } + } + c.indInG[srcNN]= cnt; } else { // COPY_ONLY - bypreG.clear(); - bypreG.resize(srcNN); - size= source.size(); - for (int i= 0; i < size; i++) { - bypreG[source[i]].push_back(gvector[i]); - } - unsigned int cnt= 0; - for (int i= 0; i < srcNN; i++) { - size= bypre[i].size(); - for (int j= 0; j < size; j++) { - gv[cnt]= bypreG[i][j]; + bypreG.clear(); + bypreG.resize(srcNN); + size= source.size(); + for (int i= 0; i < size; i++) { + bypreG[source[i]].push_back(gvector[i]); + } + unsigned int cnt= 0; + for (int i= 0; i < srcNN; i++) { + size= bypre[i].size(); + for (int j= 0; j < size; j++) { + gv[cnt]= bypreG[i][j]; // os << i << " " << c.ind[cnt] << " " << gv[cnt] << endl; - cnt++; - } - } + cnt++; + } + } + } + + // Check for duplicate entries + for (int i=0; i targets = bypre[i]; + std::sort(targets.begin(), targets.end()); + auto duplicate_pos = std::adjacent_find(targets.begin(), targets.end()); + if (duplicate_pos != targets.end()) { + std::cerr << "*****" << std::endl; + std::cerr << "ERROR Cannot run GeNN simulation: More than one synapse for pair " << source[i] << " - " << *duplicate_pos << std::endl; + std::cerr << "*****" << std::endl; + exit(222); + } } -// convertCnt++; } template @@ -101,9 +123,9 @@ void convert_dense_matrix_2_dynamic_arrays(scalar *g, int srcNN, int trgNN, vect assert(source.size() == gvector.size()); unsigned int size= source.size(); for (int i= 0; i < size; i++) { - assert(source[i] < srcNN); - assert(target[i] < trgNN); - gvector[i]= g[source[i]*trgNN+target[i]]; + assert(source[i] < srcNN); + assert(target[i] < trgNN); + gvector[i]= g[source[i]*trgNN+target[i]]; } } @@ -116,28 +138,28 @@ void convert_sparse_synapses_2_dynamic_arrays(Conductance &c, scalar *gv, int sr // ofstream os(name.c_str()); // note: this does not preserve the original order of entries in the brian arrays - is that a problem? if (mode == b2g::FULL_MONTY) { - assert(source.size() == target.size()); - assert(source.size() == gvector.size()); - unsigned int size= source.size(); - unsigned int cnt= 0; - for (int i= 0; i < srcNN; i++) { - for (int j= c.indInG[i]; j < c.indInG[i+1]; j++) { - source[cnt]= i; - target[cnt]= c.ind[j]; - gvector[cnt]= gv[j]; + assert(source.size() == target.size()); + assert(source.size() == gvector.size()); + unsigned int size= source.size(); + unsigned int cnt= 0; + for (int i= 0; i < srcNN; i++) { + for (int j= c.indInG[i]; j < c.indInG[i+1]; j++) { + source[cnt]= i; + target[cnt]= c.ind[j]; + gvector[cnt]= gv[j]; // os << source[cnt] << " " << target[cnt] << " " << gvector[cnt] << endl; - cnt++; - } - } + cnt++; + } + } } else { - unsigned int size= source.size(); - unsigned int cnt= 0; - for (int i= 0; i < srcNN; i++) { - for (int j= c.indInG[i]; j < c.indInG[i+1]; j++) { - gvector[cnt++]= gv[j]; - } - } + unsigned int size= source.size(); + unsigned int cnt= 0; + for (int i= 0; i < srcNN; i++) { + for (int j= c.indInG[i]; j < c.indInG[i+1]; j++) { + gvector[cnt++]= gv[j]; + } + } } // os.close(); // convertCnt++; @@ -146,12 +168,12 @@ void convert_sparse_synapses_2_dynamic_arrays(Conductance &c, scalar *gv, int sr void create_hidden_weightmatrix(vector &source, vector &target, char* hwm, int srcNN, int trgNN) { for (int s= 0; s < srcNN; s++) { - for (int t= 0; t < trgNN; t++) { - hwm[s*trgNN+t]= 0; - } + for (int t= 0; t < trgNN; t++) { + hwm[s*trgNN+t]= 0; + } } for (int i= 0; i < source.size(); i++) { - hwm[source[i]*trgNN+target[i]]= 1; + hwm[source[i]*trgNN+target[i]]= 1; } } #endif diff --git a/brian2genn/device.py b/brian2genn/device.py index 21998e97..0a7d8579 100644 --- a/brian2genn/device.py +++ b/brian2genn/device.py @@ -677,12 +677,17 @@ def build(self, directory='GeNNworkspace', compile=True, run=True, try: self.run(directory, use_GPU, with_output) except CalledProcessError as ex: - raise RuntimeError(('Project run failed (Command {cmd} ' - 'failed with error code {returncode}).\n' - 'See the output above (if any) for more ' - 'details.').format(cmd=ex.cmd, - returncode=ex.returncode) - ) + if ex.returncode == 222: + raise NotImplementedError('GeNN does not support multiple ' + 'synapses per neuron pair (use ' + 'multiple Synapses objects).') + else: + raise RuntimeError(('Project run failed (Command {cmd} ' + 'failed with error code {returncode}).\n' + 'See the output above (if any) for more ' + 'details.').format(cmd=ex.cmd, + returncode=ex.returncode) + ) def generate_code_objects(self, writer): # Generate data for non-constant values