示例#1
0
	def generate_helpers_C(self, chunk_size=100):
		"""
		translates the helpers to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_.
		
		Parameters
		----------
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your helpers, the group size suggests itself for `chunk_size`.
			
			If smaller than 1, no chunking will happen.
		"""
		
		render_declarations(
			(helper[0] for helper in self.helpers),
			self._tmpfile("declare_general_helpers.c")
			)
		
		render_and_write_code(
			[],
			self.helpers,
			self._tmpfile(),
			"helpers",
			{"y":"y"},
			chunk_size = chunk_size
			)
示例#2
0
	def generate_helpers_C(self, chunk_size=100):
		"""
		translates the helpers to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_.
		
		Parameters
		----------
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your helpers, the group size suggests itself for `chunk_size`.
			
			If smaller than 1, no chunking will happen.
		"""
		
		if self.helpers:
			get_helper = sympy.Function("get_general_helper")
			set_helper = sympy.Function("set_general_helper")
			
			self.helper_subs = [(helper[0],get_helper(i)) for i,helper in enumerate(self.helpers)]
			render_and_write_code(
				(set_helper(i, helper[1].subs(self.helper_subs)) for i,helper in enumerate(self.helpers)),
				self._tmpfile,
				"general_helpers",
				["y", "get_general_helper", "set_general_helper"],
				chunk_size = chunk_size,
				arguments = [("Y", "PyArrayObject *restrict const"), ("general_helper","double *restrict const")]
				)
		
		self._helper_C_source = True
示例#3
0
	def generate_jac_C(self, do_cse=False, chunk_size=100, sparse=True):
		"""
		translates the symbolic Jacobian to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_. If the symbolic Jacobian has not been generated, it generates it by calling `generate_jac_sym`.
		
		Parameters
		----------
		
		do_cse : boolean
			Whether SymPy’s `common-subexpression detection <http://docs.sympy.org/dev/modules/rewriting.html#module-sympy.simplify.cse_main>`_ should be applied before translating to C code. It is almost always better to let the compiler do this (unless you want to set the compiler optimisation to `-O2` or lower): For simple differential equations this should not make any difference to the compiler’s optimisations. For large ones, it may make a difference but also take long. As this requires the entire Jacobian at once, it may void advantages gained from using generator functions as an input.
			
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your Jacobian, the respective group size suggests itself for `chunk_size`. For example, the derivative of each dynamical variable explicitly depends on 60 others and the Jacobian is sparse, a chunk size of 60 suggests itself.
			
			If smaller than 1, no chunking will happen.
		
		sparse : boolean
			Whether a sparse Jacobian should be assumed for optimisation. Note that this does not mean that the Jacobian is stored, parsed or handled as a sparse matrix. This kind of optimisation would require SciPy’s ODE to be able to handle sparse matrices.
		"""
		
		self._generate_jac_sym()
		jac_sym_wc = self.jac_sym
		self.sparse_jac = sparse
		
		if do_cse:
			jac_matrix = sympy.Matrix([ [entry for entry in line] for line in jac_sym_wc ])
			
			_cse = sympy.cse(
					jac_matrix,
					symbols = sympy.numbered_symbols("dummy_jac_")
				)
			more_helpers = _cse[0]
			jac_sym_wc = _cse[1][0].tolist()
		else:
			more_helpers = []
		
		render_declarations(
			(helper[0] for helper in more_helpers),
			self._tmpfile("declare_jac_helpers.c")
			)
		
		set_dfdy = sympy.Function("set_dfdy")
		render_and_write_code(
			(
				set_dfdy(i,j,entry)
				for i,line in enumerate(jac_sym_wc)
				for j,entry in enumerate(line)
				if ( (entry != 0) or not self.sparse_jac )
			),
			more_helpers,
			self._tmpfile(),
			"jac",
			{"set_dfdy":"set_dfdy", "y":"y"},
			chunk_size = chunk_size
			)
		
		self._jac_C_source = True
示例#4
0
	def generate_f_C(self, simplify=True, do_cse=False, chunk_size=100):
		"""
		translates the derivative to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_.
		
		Parameters
		----------
		simplify : boolean
			Whether the derivative should be `simplified <http://docs.sympy.org/dev/modules/simplify/simplify.html>`_ (with `ratio=1.0`) before translating to C code. The main reason why you could want to disable this is if your derivative is already  optimised and so large that simplifying takes a considerable amount of time.
		
		do_cse : boolean
			Whether SymPy’s `common-subexpression detection <http://docs.sympy.org/dev/modules/rewriting.html#module-sympy.simplify.cse_main>`_ should be applied before translating to C code. It is almost always better to let the compiler do this (unless you want to set the compiler optimisation to `-O2` or lower): For simple differential equations this should not make any difference to the compiler’s optimisations. For large ones, it may make a difference but also take long. As this requires all entries of `f` at once, it may void advantages gained from using generator functions as an input.
		
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your :math:`f`, the group size suggests itself for `chunk_size`. For example, if you want to simulate the dynamics of three-dimensional oscillators coupled onto a 40×40 lattice and if the differential equations are grouped first by oscillator and then by lattice row, a chunk size of 120 suggests itself.
			
			If smaller than 1, no chunking will happen.
		"""
		
		f_sym_wc = self.f_sym()
		
		if simplify:
			f_sym_wc = (sympy.simplify(entry,ratio=1) for entry in f_sym_wc)
		
		if do_cse:
			_cse = sympy.cse(
					sympy.Matrix(list(self.f_sym())),
					symbols = sympy.numbered_symbols("dummy_f_")
				)
			more_helpers = _cse[0]
			f_sym_wc = _cse[1][0]
		else:
			more_helpers = []
		
		render_declarations(
			(helper[0] for helper in more_helpers),
			self._tmpfile("declare_f_helpers.c")
			)
		
		set_dy = sympy.Function("set_dy")
		render_and_write_code(
			(set_dy(i,entry) for i,entry in enumerate(f_sym_wc)),
			more_helpers,
			self._tmpfile(),
			"f",
			{"set_dy":"set_dy", "y":"y"},
			chunk_size = chunk_size
			)
		
		self._f_C_source = True
示例#5
0
	def generate_jac_C(self, do_cse=False, chunk_size=100, sparse=True):
		"""
		translates the symbolic Jacobian to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_. If the symbolic Jacobian has not been generated, it generates it by calling `generate_jac_sym`.
		
		Parameters
		----------
		
		do_cse : boolean
			Whether SymPy’s `common-subexpression detection <http://docs.sympy.org/dev/modules/rewriting.html#module-sympy.simplify.cse_main>`_ should be applied before translating to C code. It is almost always better to let the compiler do this (unless you want to set the compiler optimisation to `-O2` or lower): For simple differential equations this should not make any difference to the compiler’s optimisations. For large ones, it may make a difference but also take long. As this requires the entire Jacobian at once, it may void advantages gained from using generator functions as an input.
			
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your Jacobian, the respective group size suggests itself for `chunk_size`. For example, the derivative of each dynamical variable explicitly depends on 60 others and the Jacobian is sparse, a chunk size of 60 suggests itself.
			
			If smaller than 1, no chunking will happen.
		
		sparse : boolean
			Whether a sparse Jacobian should be assumed for optimisation. Note that this does not mean that the Jacobian is stored, parsed or handled as a sparse matrix. This kind of optimisation would require SciPy’s ODE to be able to handle sparse matrices.
		"""
		
		self._generate_helpers_C()
		self._generate_jac_sym()
		
		jac_sym_wc = sympy.Matrix([ [entry.subs(self.helper_subs) for entry in line] for line in self.jac_sym ])
		self.sparse_jac = sparse
		
		arguments = [("Y", "PyArrayObject *restrict const")]
		if self._number_of_general_helpers:
			arguments.append(("general_helper","double const *restrict const"))
		
		if do_cse:
			get_helper = sympy.Function("get_jac_helper")
			set_helper = sympy.Function("set_jac_helper")
			
			_cse = sympy.cse(
					jac_sym_wc,
					symbols = (get_helper(i) for i in count())
				)
			more_helpers = _cse[0]
			jac_sym_wc = _cse[1][0]
			
			if more_helpers:
				arguments.append(("jac_helper","double *restrict const"))
				render_and_write_code(
					(set_helper(i, helper[1]) for i,helper in enumerate(more_helpers)),
					self._tmpfile,
					"jac_helpers",
					["y", "get_jac_helper", "set_jac_helper", "get_general_helper"],
					chunk_size = chunk_size,
					arguments = arguments
					)
				self._number_of_jac_helpers = len(more_helpers)
		
		jac_sym_wc = jac_sym_wc.tolist()
		
		set_dfdy = sympy.Function("set_dfdy")
		
		render_and_write_code(
			(
				set_dfdy(i,j,entry)
				for i,line in enumerate(jac_sym_wc)
				for j,entry in enumerate(line)
				if ( (entry != 0) or not self.sparse_jac )
			),
			self._tmpfile,
			"jac",
			["set_dfdy", "y", "get_jac_helper", "get_general_helper"],
			chunk_size = chunk_size,
			arguments = arguments+[("dfdY", "PyArrayObject *restrict const")]
		)
		
		self._jac_C_source = True
示例#6
0
	def generate_f_C(self, simplify=True, do_cse=False, chunk_size=100):
		"""
		translates the derivative to C code using SymPy’s `C-code printer <http://docs.sympy.org/dev/modules/printing.html#module-sympy.printing.ccode>`_.
		
		Parameters
		----------
		simplify : boolean
			Whether the derivative should be `simplified <http://docs.sympy.org/dev/modules/simplify/simplify.html>`_ (with `ratio=1.0`) before translating to C code. The main reason why you could want to disable this is if your derivative is already  optimised and so large that simplifying takes a considerable amount of time.
		
		do_cse : boolean
			Whether SymPy’s `common-subexpression detection <http://docs.sympy.org/dev/modules/rewriting.html#module-sympy.simplify.cse_main>`_ should be applied before translating to C code. It is almost always better to let the compiler do this (unless you want to set the compiler optimisation to `-O2` or lower): For simple differential equations this should not make any difference to the compiler’s optimisations. For large ones, it may make a difference but also take long. As this requires all entries of `f` at once, it may void advantages gained from using generator functions as an input.
		
		chunk_size : integer
			If the number of instructions in the final C code exceeds this number, it will be split into chunks of this size. After the generation of each chunk, SymPy’s cache is cleared. See `large_systems` on why this is useful.
			
			If there is an obvious grouping of your :math:`f`, the group size suggests itself for `chunk_size`. For example, if you want to simulate the dynamics of three-dimensional oscillators coupled onto a 40×40 lattice and if the differential equations are grouped first by oscillator and then by lattice row, a chunk size of 120 suggests itself.
			
			If smaller than 1, no chunking will happen.
		"""
		
		self._generate_helpers_C()
		
		f_sym_wc = self.f_sym()
		
		if simplify:
			f_sym_wc = (sympy.simplify(entry,ratio=1) for entry in f_sym_wc)
		
		if self.helpers:
			f_sym_wc = (entry.subs(self.helper_subs) for entry in f_sym_wc)
		
		arguments = [("Y", "PyArrayObject *restrict const")]
		if self._number_of_general_helpers:
			arguments.append(("general_helper","double const *restrict const"))
		
		if do_cse:
			get_helper = sympy.Function("get_f_helper")
			set_helper = sympy.Function("set_f_helper")
			
			_cse = sympy.cse(
					sympy.Matrix(list(f_sym_wc)),
					symbols = (get_helper(i) for i in count())
				)
			more_helpers = _cse[0]
			f_sym_wc = _cse[1][0]
			
			if more_helpers:
				arguments.append(("f_helper","double *restrict const"))
				render_and_write_code(
					(set_helper(i, helper[1]) for i,helper in enumerate(more_helpers)),
					self._tmpfile,
					"f_helpers",
					["y", "get_f_helper", "set_f_helper", "get_general_helper"],
					chunk_size = chunk_size,
					arguments = arguments
					)
				self._number_of_f_helpers = len(more_helpers)
		
		set_dy = sympy.Function("set_dy")
		render_and_write_code(
			(set_dy(i,entry) for i,entry in enumerate(f_sym_wc)),
			self._tmpfile,
			"f",
			["set_dy", "y", "get_f_helper", "get_general_helper"],
			chunk_size = chunk_size,
			arguments = arguments+[("dY", "PyArrayObject *restrict const")]
			)
		
		self._f_C_source = True