def translate_expression(self, expr): for varname, var in self.variables.iteritems(): if isinstance(var, Function): impl_name = var.implementations[self.codeobj_class].name if impl_name is not None: expr = word_substitute(expr, {varname: impl_name}) return CPPNodeRenderer().render_expr(expr).strip()
def translate_expression(self, expr): for varname, var in self.variables.iteritems(): if isinstance(var, Function): try: impl_name = var.implementations[self.codeobj_class].name except KeyError: raise NotImplementedError('Function {} is not available ' 'for use with ' 'GeNN.'.format(var.name)) if impl_name is not None: expr = word_substitute(expr, {varname: impl_name}) return CPPNodeRenderer().render_expr(expr).strip()
def fill_with_array(self, var, arr): arr = np.asarray(arr) array_name = self.get_array_name(var, access_data=False) arr = np.asarray(arr) if arr.shape == (): if var.size == 1: value = CPPNodeRenderer().render_expr(repr(arr.item(0))) # For a single assignment, generate a code line instead of storing the array self.main_queue.append( ('set_by_single_value', (array_name, 0, value))) else: self.main_queue.append( ('set_by_constant', (array_name, arr.item()))) else: # Using the std::vector instead of a pointer to the underlying # data for dynamic arrays is fast enough here and it saves us some # additional work to set up the pointer static_array_name = self.static_array(array_name, arr) self.main_queue.append( ('set_by_array', (array_name, static_array_name)))
def freeze(code, ns): # this is a bit of a hack, it should be passed to the template somehow for k, v in ns.items(): if (isinstance(v, Variable) and not isinstance(v, AttributeVariable) and v.scalar and v.constant and v.read_only): v = v.get_value() if isinstance(v, basestring): code = word_substitute(code, {k: v}) elif isinstance(v, numbers.Number): # Use a renderer to correctly transform constants such as True or inf renderer = CPPNodeRenderer() string_value = renderer.render_expr(repr(v)) if v < 0: string_value = '(%s)' % string_value code = word_substitute(code, {k: string_value}) else: pass # don't deal with this object return code
def translate_expression(self, expr): expr = word_substitute(expr, self.func_name_replacements) return CPPNodeRenderer().render_expr(expr).strip()
def test_parse_expressions_cpp(): if prefs.codegen.target != 'weave': pytest.skip('weave-only test') parse_expressions(CPPNodeRenderer(), cpp_evaluator)
def test_parse_expressions_cpp(): parse_expressions(CPPNodeRenderer(), cpp_evaluator)
def generate_main_source(self, writer): main_lines = [] procedures = [('', main_lines)] runfuncs = {} for func, args in self.main_queue: if func=='run_code_object': codeobj, = args main_lines.append('_run_%s();' % codeobj.name) elif func=='run_network': net, netcode = args main_lines.extend(netcode) elif func=='set_by_constant': arrayname, value, is_dynamic = args size_str = arrayname+'.size()' if is_dynamic else '_num_'+arrayname code = ''' {pragma} for(int i=0; i<{size_str}; i++) {{ {arrayname}[i] = {value}; }} '''.format(arrayname=arrayname, size_str=size_str, value=CPPNodeRenderer().render_expr(repr(value)), pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func=='set_by_array': arrayname, staticarrayname, is_dynamic = args size_str = arrayname+'.size()' if is_dynamic else '_num_'+arrayname code = ''' {pragma} for(int i=0; i<{size_str}; i++) {{ {arrayname}[i] = {staticarrayname}[i]; }} '''.format(arrayname=arrayname, size_str=size_str, staticarrayname=staticarrayname, pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func=='set_by_single_value': arrayname, item, value = args code = '{arrayname}[{item}] = {value};'.format(arrayname=arrayname, item=item, value=value) main_lines.extend([code]) elif func=='set_array_by_array': arrayname, staticarrayname_index, staticarrayname_value = args code = ''' {pragma} for(int i=0; i<_num_{staticarrayname_index}; i++) {{ {arrayname}[{staticarrayname_index}[i]] = {staticarrayname_value}[i]; }} '''.format(arrayname=arrayname, staticarrayname_index=staticarrayname_index, staticarrayname_value=staticarrayname_value, pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func=='resize_array': array_name, new_size = args main_lines.append("{array_name}.resize({new_size});".format(array_name=array_name, new_size=new_size)) elif func=='insert_code': main_lines.append(args) elif func=='start_run_func': name, include_in_parent = args if include_in_parent: main_lines.append('%s();' % name) main_lines = [] procedures.append((name, main_lines)) elif func=='end_run_func': name, include_in_parent = args name, main_lines = procedures.pop(-1) runfuncs[name] = main_lines name, main_lines = procedures[-1] elif func=='seed': seed = args nb_threads = prefs.devices.cpp_standalone.openmp_threads if nb_threads == 0: # no OpenMP nb_threads = 1 main_lines.append('for (int _i=0; _i<{nb_threads}; _i++)'.format(nb_threads=nb_threads)) if seed is None: # random main_lines.append(' rk_randomseed(brian::_mersenne_twister_states[_i]);') else: main_lines.append(' rk_seed({seed!r}L + _i, brian::_mersenne_twister_states[_i]);'.format(seed=seed)) else: raise NotImplementedError("Unknown main queue function type "+func) self.runfuncs = runfuncs # generate the finalisations for codeobj in self.code_objects.itervalues(): if hasattr(codeobj.code, 'main_finalise'): main_lines.append(codeobj.code.main_finalise) # The code_objects are passed in the right order to run them because they were # sorted by the Network object. To support multiple clocks we'll need to be # smarter about that. main_tmp = self.code_object_class().templater.main(None, None, main_lines=main_lines, code_objects=self.code_objects.values(), report_func=self.report_func, dt=float(self.defaultclock.dt), user_headers=self.headers ) writer.write('main.cpp', main_tmp)
def generate_main_source(self, writer): main_lines = [] procedures = [('', main_lines)] runfuncs = {} for func, args in self.main_queue: if func == 'run_code_object': codeobj, = args main_lines.append('_run_%s();' % codeobj.name) elif func == 'run_network': net, netcode = args main_lines.extend(netcode) elif func == 'set_by_constant': arrayname, value = args code = ''' {pragma} for(int i=0; i<_num_{arrayname}; i++) {{ {arrayname}[i] = {value}; }} '''.format(arrayname=arrayname, value=CPPNodeRenderer().render_expr(repr(value)), pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func == 'set_by_array': arrayname, staticarrayname = args code = ''' {pragma} for(int i=0; i<_num_{staticarrayname}; i++) {{ {arrayname}[i] = {staticarrayname}[i]; }} '''.format(arrayname=arrayname, staticarrayname=staticarrayname, pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func == 'set_by_single_value': arrayname, item, value = args code = '{arrayname}[{item}] = {value};'.format( arrayname=arrayname, item=item, value=value) main_lines.extend([code]) elif func == 'set_array_by_array': arrayname, staticarrayname_index, staticarrayname_value = args code = ''' {pragma} for(int i=0; i<_num_{staticarrayname_index}; i++) {{ {arrayname}[{staticarrayname_index}[i]] = {staticarrayname_value}[i]; }} '''.format(arrayname=arrayname, staticarrayname_index=staticarrayname_index, staticarrayname_value=staticarrayname_value, pragma=openmp_pragma('static')) main_lines.extend(code.split('\n')) elif func == 'resize_array': array_name, new_size = args main_lines.append("{array_name}.resize({new_size});".format( array_name=array_name, new_size=new_size)) elif func == 'insert_code': main_lines.append(args) elif func == 'start_run_func': name, include_in_parent = args if include_in_parent: main_lines.append('%s();' % name) main_lines = [] procedures.append((name, main_lines)) elif func == 'end_run_func': name, include_in_parent = args name, main_lines = procedures.pop(-1) runfuncs[name] = main_lines name, main_lines = procedures[-1] else: raise NotImplementedError("Unknown main queue function type " + func) self.runfuncs = runfuncs # generate the finalisations for codeobj in self.code_objects.itervalues(): if hasattr(codeobj.code, 'main_finalise'): main_lines.append(codeobj.code.main_finalise) # The code_objects are passed in the right order to run them because they were # sorted by the Network object. To support multiple clocks we'll need to be # smarter about that. main_tmp = CPPStandaloneCodeObject.templater.main( None, None, main_lines=main_lines, code_objects=self.code_objects.values(), report_func=self.report_func, dt=float(defaultclock.dt), user_headers=prefs['codegen.cpp.headers']) writer.write('main.cpp', main_tmp)
def variableview_set_with_index_array(self, variableview, item, value, check_units): if isinstance(item, slice) and item == slice(None): item = 'True' value = Quantity(value) if (isinstance(item, int) or (isinstance(item, np.ndarray) and item.shape == ())) and value.size == 1: array_name = self.get_array_name(variableview.variable, access_data=False) value = CPPNodeRenderer().render_expr( repr(np.asarray(value).item(0))) # For a single assignment, generate a code line instead of storing the array self.main_queue.append( ('set_by_single_value', (array_name, item, value))) elif (value.size == 1 and item == 'True' and variableview.index_var_name == '_idx'): # set the whole array to a scalar value if have_same_dimensions(value, 1): # Avoid a representation as "Quantity(...)" or "array(...)" value = float(value) variableview.set_with_expression_conditional( cond=item, code=repr(value), check_units=check_units) # Simple case where we don't have to do any indexing elif (item == 'True' and variableview.index_var == '_idx'): self.fill_with_array(variableview.variable, value) else: # We have to calculate indices. This will not work for synaptic # variables try: indices = np.asarray( variableview.indexing(item, index_var=variableview.index_var)) except NotImplementedError: raise NotImplementedError( ('Cannot set variable "%s" this way in ' 'standalone, try using string ' 'expressions.') % variableview.name) # Using the std::vector instead of a pointer to the underlying # data for dynamic arrays is fast enough here and it saves us some # additional work to set up the pointer arrayname = self.get_array_name(variableview.variable, access_data=False) if indices.shape == (): self.main_queue.append( ('set_by_single_value', (arrayname, indices.item(), float(value)))) else: staticarrayname_index = self.static_array( '_index_' + arrayname, indices) staticarrayname_value = self.static_array( '_value_' + arrayname, value) self.main_queue.append( ('set_array_by_array', (arrayname, staticarrayname_index, staticarrayname_value))) staticarrayname_index = self.static_array('_index_' + arrayname, indices) if (indices.shape != () and (value.shape == () or (value.size == 1 and indices.size > 1))): value = np.repeat(value, indices.size) staticarrayname_value = self.static_array('_value_' + arrayname, value) self.main_queue.append( ('set_array_by_array', (arrayname, staticarrayname_index, staticarrayname_value)))
def generate_main_source(self, writer, main_includes): main_lines = [] procedures = [('', main_lines)] runfuncs = {} for func, args in self.main_queue: if func == 'run_code_object': codeobj, = args codeobj.runs_every_tick = False main_lines.append('_run_%s();' % codeobj.name) elif func == 'run_network': net, netcode = args for clock in net._clocks: line = "{net.name}.add(&{clock.name}, _sync_clocks);".format( clock=clock, net=net) netcode.insert(1, line) main_lines.extend(netcode) elif func == 'set_by_constant': arrayname, value, is_dynamic = args size_str = arrayname + ".size()" if is_dynamic else "_num_" + arrayname code = ''' for(int i=0; i<{size_str}; i++) {{ {arrayname}[i] = {value}; }} '''.format(arrayname=arrayname, size_str=size_str, value=CPPNodeRenderer().render_expr(repr(value))) main_lines.extend(code.split('\n')) pointer_arrayname = "dev{arrayname}".format( arrayname=arrayname) if arrayname.endswith('space'): # eventspace pointer_arrayname += '[current_idx{arrayname}]'.format( arrayname=arrayname) if is_dynamic: pointer_arrayname = "thrust::raw_pointer_cast(&dev{arrayname}[0])".format( arrayname=arrayname) line = "cudaMemcpy({pointer_arrayname}, &{arrayname}[0], sizeof({arrayname}[0])*{size_str}, cudaMemcpyHostToDevice);".format( arrayname=arrayname, size_str=size_str, pointer_arrayname=pointer_arrayname, value=CPPNodeRenderer().render_expr(repr(value))) main_lines.extend([line]) elif func == 'set_by_single_value': arrayname, item, value = args pointer_arrayname = "dev{arrayname}".format( arrayname=arrayname) if arrayname in self.dynamic_arrays.values(): pointer_arrayname = "thrust::raw_pointer_cast(&dev{arrayname}[0])".format( arrayname=arrayname) code = ''' {arrayname}[{item}] = {value}; cudaMemcpy(&{pointer_arrayname}[{item}], &{arrayname}[{item}], sizeof({arrayname}[0]), cudaMemcpyHostToDevice); '''.format(pointer_arrayname=pointer_arrayname, arrayname=arrayname, item=item, value=value) main_lines.extend([code]) elif func == 'set_by_array': arrayname, staticarrayname, is_dynamic = args size = "_num_" + arrayname if is_dynamic: size = arrayname + ".size()" code = ''' for(int i=0; i<_num_{staticarrayname}; i++) {{ {arrayname}[i] = {staticarrayname}[i]; }} '''.format(arrayname=arrayname, staticarrayname=staticarrayname, size_str=size) pointer_arrayname = "dev{arrayname}".format( arrayname=arrayname) if arrayname in self.dynamic_arrays.values(): pointer_arrayname = "thrust::raw_pointer_cast(&dev{arrayname}[0])".format( arrayname=arrayname) main_lines.extend(code.split('\n')) line = ''' cudaMemcpy({pointer_arrayname}, &{arrayname}[0], sizeof({arrayname}[0])*{size_str}, cudaMemcpyHostToDevice); '''.format(pointer_arrayname=pointer_arrayname, staticarrayname=staticarrayname, size_str=size, arrayname=arrayname) main_lines.extend([line]) elif func == 'set_array_by_array': arrayname, staticarrayname_index, staticarrayname_value = args code = ''' for(int i=0; i<_num_{staticarrayname_index}; i++) {{ {arrayname}[{staticarrayname_index}[i]] = {staticarrayname_value}[i]; }} cudaMemcpy(dev{arrayname}, &{arrayname}[0], sizeof({arrayname}[0])*_num_{arrayname}, cudaMemcpyHostToDevice); '''.format(arrayname=arrayname, staticarrayname_index=staticarrayname_index, staticarrayname_value=staticarrayname_value) main_lines.extend(code.split('\n')) elif func == 'resize_array': array_name, new_size = args main_lines.append(''' {array_name}.resize({new_size}); dev{array_name}.resize({new_size}); '''.format(array_name=array_name, new_size=new_size)) elif func == 'insert_code': main_lines.append(args) elif func == 'start_run_func': name, include_in_parent = args if include_in_parent: main_lines.append('%s();' % name) main_lines = [] procedures.append((name, main_lines)) elif func == 'end_run_func': name, include_in_parent = args name, main_lines = procedures.pop(-1) runfuncs[name] = main_lines name, main_lines = procedures[-1] elif func == 'seed': seed = args if seed is not None: main_lines.append( 'curandSetPseudoRandomGeneratorSeed(random_float_generator, {seed!r}ULL);' .format(seed=seed)) # generator offset needs to be reset to its default (=0) main_lines.append( 'curandSetGeneratorOffset(random_float_generator, 0ULL);' ) # else a random seed is set in objects.cu::_init_arrays() else: raise NotImplementedError("Unknown main queue function type " + func) # generate the finalisations for codeobj in self.code_objects.itervalues(): if hasattr(codeobj.code, 'main_finalise'): main_lines.append(codeobj.code.main_finalise) main_tmp = CUDAStandaloneCodeObject.templater.main( None, None, main_lines=main_lines, code_objects=self.code_objects.values(), report_func=self.report_func, dt=float(defaultclock.dt), additional_headers=main_includes) writer.write('main.cu', main_tmp)
def translate_expression(self, expr): return CPPNodeRenderer().render_expr(expr).strip()