コード例 #1
0
    def generate_helpers_C(self, chunk_size=100):
        """
		translates the helpers to C code using SymEngine’s `C-code printer <https://github.com/symengine/symengine/pull/1054>`_.
		
		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. 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 = symengine.Function("get_general_helper")
            set_helper = symengine.Function("set_general_helper")

            for i, helper in enumerate(self.helpers):
                self.general_subs[helper[0]] = get_helper(i)
            self.render_and_write_code(
                (set_helper(i, helper[1].subs(self.general_subs))
                 for i, helper in enumerate(self.helpers)),
                name="general_helpers",
                chunk_size=chunk_size,
                arguments=self._default_arguments() +
                [("general_helper", "double *__restrict const")],
                omp=False,
            )

        self._helper_C_source = True
コード例 #2
0
ファイル: neural_mass.py プロジェクト: nikmerlock97/neurolib
    def __init__(self, params, seed=None):
        """
        :param params: parameters of the neural mass
        :type params: dict
        :param seed: seed for random number generator
        :type seed: int|None
        """
        assert isinstance(params, dict)
        self.params = deepcopy(params)
        self.seed = seed
        # used in determining portion of the full system's state vector
        self.idx_state_var = None
        self.initialised = False

        # initialise possible helpers
        self.helper_symbols = {
            symbol: se.Symbol(symbol)
            for symbol in self.helper_variables
        }

        # initialise possible callback functions
        self.callback_functions = {
            function: se.Function(function)
            for function in self.python_callbacks
        }

        self._validate_params()
コード例 #3
0
    def __init__(self,
                 f_sym=(),
                 groups=(),
                 simplify=None,
                 average_dynamics=False,
                 **kwargs):
        GroupHandler.__init__(self, groups)
        self.n = kwargs.pop("n", None)

        f_basic, extracted = self.extract_main(self._handle_input(f_sym))
        helpers = sort_helpers(sympify_helpers(kwargs.pop("helpers", [])))

        if simplify is None:
            simplify = self.n <= 10

        z = symengine.Function("z")
        z_vector = [z(i) for i in range(self.n)]
        tangent_vector = self.back_transform(z_vector)

        def tangent_vector_f():
            for line in _jac_from_f_with_helpers(f=f_basic,
                                                 helpers=helpers,
                                                 simplify=False,
                                                 n=self.n):
                yield sum(entry * tangent_vector[k]
                          for k, entry in enumerate(line) if entry)

        substitutions = {y(i): z(self.map_to_main(i)) for i in range(self.n)}

        def finalise(entry):
            entry = entry.subs(substitutions)
            if simplify:
                entry = entry.simplify(ratio=1)
            return replace_function(entry, z, y)

        if average_dynamics:
            f_list = list(f_basic())

        def f_lyap():
            for entry in self.iterate(tangent_vector_f()):
                if type(entry) == int:  # i.e., if main index
                    if average_dynamics:
                        group = groups[entry]
                        yield sum(finalise(f_list[i])
                                  for i in group) / len(group)
                    else:
                        yield finalise(extracted[self.main_indices[entry]])
                else:
                    yield finalise(entry[0] - entry[1])

        helpers = ((helper[0], finalise(helper[1])) for helper in helpers)

        super(jitcode_transversal_lyap, self).__init__(f_lyap,
                                                       helpers=helpers,
                                                       n=self.n,
                                                       **kwargs)
コード例 #4
0
    def test_back_transform(self):
        z = symengine.Function("z")

        z_v = [z(i) for i in range(self.n)]
        y_v = self.G.back_transform(z_v)

        transformed = []
        for entry in self.G.iterate(range(self.n)):
            if type(entry) == int:
                transformed.append(sum(y_v[i] for i in self.groups[entry]))
            else:
                transformed.append(y_v[entry[0]] - y_v[entry[1]])

        for i in self.G.main_indices:
            z_v[i] = 0
        self.assertSequenceEqual(z_v,
                                 [entry.simplify() for entry in transformed])
コード例 #5
0
ファイル: test_jitcdde.py プロジェクト: dw-liedji/jitcdde
	def test_midpoint(self):
		f = symengine.Function("f")
		t = symengine.Symbol("t")
		control = (f(1)+f(3)+f(5)+f(7)+f(9))*2
		result = quadrature(f(t),t,0,10,nsteps=5,method="midpoint")
		self.assertEqual(control,result)
コード例 #6
0
ファイル: test_sympy_input.py プロジェクト: dw-liedji/jitcdde
def sympy_y(index,time=sympy_t):
	if time == sympy_t:
		return sympy_current_y(index)
	else:
		return sympy_past_y(time, index, sympy_anchors(time))
sympy_current_y = sympy.Function("current_y",real=True)
sympy_past_y = sympy.Function("past_y",real=True)
sympy_anchors = sympy.Function("anchors",real=True)

symengine_t = symengine.Symbol("t",real=True)
def symengine_y(index,time=symengine_t):
	if time == symengine_t:
		return symengine_current_y(index)
	else:
		return symengine_past_y(time, index, symengine_anchors(time))
symengine_current_y = symengine.Function("current_y",real=True)
symengine_past_y = symengine.Function("past_y",real=True)
symengine_anchors = symengine.Function("anchors",real=True)


symengine_manually = [
		symengine_t,
		symengine_y,
		symengine.cos,
	]

sympy_manually = [
		sympy_t,
		sympy_y,
		sympy.cos,
	]
コード例 #7
0
ファイル: _jitcsde.py プロジェクト: neurophysik/jitcsde
	def compile_C(
			self,
			simplify = None,
			do_cse = False,
			numpy_rng = False,
			chunk_size = 100,
			extra_compile_args = None,
			extra_link_args = None,
			verbose = False,
			modulename = None,
			omp = False,
		):
		"""
		translates the derivative to C code using SymEngine’s `C-code printer <https://github.com/symengine/symengine/pull/1054>`_.
		For detailed information many of the arguments and other ways to tweak the compilation, read `these notes <jitcde-common.readthedocs.io>`_.
		
		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. If `None`, this will be automatically disabled for `n>10`.
		
		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). As this requires all entries of `f` and `g` at once, it may void advantages gained from using generator functions as an input. Also, this feature uses SymPy and not SymEngine.
		
		numpy_rng : boolean
			Whether `numpy.random.normal` shall be explicitly employed for generating random numbers. This is less efficient and mainly exists for testing purposes to ensure that the random numbers are the same as when using the Python backend. Note that the alternative is still based on the same code as NumPy’s random-number generator (until somebody changes it) and should produce the same results. Also note that details in the arithmetic realisation may still cause tiny differences in the results from the two backends, which can then be magnified by the butterfly effect.
		
		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. See `Handling very large differential equations <http://jitcde-common.readthedocs.io/#handling-very-large-differential-equations>`_ on why this is useful and how to best choose this value.
			If smaller than 1, no chunking will happen.
		
		extra_compile_args : iterable of strings
		extra_link_args : iterable of strings
			Arguments to be handed to the C compiler or linker, respectively.
		
		verbose : boolean
			Whether the compiler commands shall be shown. This is the same as Setuptools’ `verbose` setting.

		modulename : string or `None`
			The name used for the compiled module.
		
		omp : pair of iterables of strings or boolean
			What compiler arguments shall be used for multiprocessing (using OpenMP). If `True`, they will be selected automatically. If empty or `False`, no compilation for multiprocessing will happen (unless you supply the relevant compiler arguments otherwise).
		"""
		
		self.compile_attempt = False
		
		if simplify is None:
			simplify = self.n<=10
		
		helper_lengths = dict()
		
		for sym,helpers,name,long_name in [
					( self.f_sym, self._f_helpers, "f", "drift"     ),
					( self.g_sym, self._g_helpers, "g", "diffusion" )
				]:
			setter_name = "set_" + long_name
			wc = sym()
			helpers_wc = copy_helpers(helpers)
			
			if simplify:
				wc = (entry.simplify(ratio=1.0) for entry in wc)
			
			if do_cse:
				import sympy
				additional_helper = sympy.Function("additional_"+name+"_helper")
				
				_cse = sympy.cse(
						sympy.Matrix(sympy.sympify(list(wc))),
						symbols = (additional_helper(i) for i in count())
					)
				helpers_wc.extend(symengine.sympify(_cse[0]))
				wc = symengine.sympify(_cse[1][0])
			
			arguments = [
					("self", "sde_integrator * const"),
					("t", "double const"),
					(long_name, "double", self.n),
				]
			if name=="f" or not self.additive:
				arguments.append( ("Y","double",self.n) )
			if name=="f":
				arguments.append( ("h","double") )
			
			functions = ["y"]
			self.substitutions = {
					control_par: symengine.Symbol("self->parameter_"+control_par.name)
					for control_par in self.control_pars
				}
			
			def finalise(expression):
				return expression.subs(self.substitutions)
			
			if helpers_wc:
				converted_helpers = []
				get_helper = symengine.Function("get_"+name+"_helper")
				set_helper = symengine.Function("set_"+name+"_helper")
				
				for i,helper in enumerate(helpers_wc):
					converted_helpers.append(set_helper(i, finalise(helper[1])))
					self.substitutions[helper[0]] = get_helper(i)
				
				extra_arguments = [(name, "double", len(helpers_wc))]
				functions.extend(["get_"+name+"_helper", "set_"+name+"_helper"])
				
				self.render_and_write_code(
						converted_helpers,
						name = name + "_helpers",
						chunk_size = chunk_size,
						arguments = arguments + extra_arguments
					)
			
			setter = symengine.Function(setter_name)
			self.render_and_write_code(
					(setter(i,finalise(entry)) for i,entry in enumerate(wc)),
					name = name,
					chunk_size = chunk_size,
					arguments = arguments
				)
			
			helper_lengths[name] = len(helpers_wc)
		
		self._process_modulename(modulename)
		
		self._render_template(
				n = self.n,
				number_of_f_helpers = helper_lengths["f"],
				number_of_g_helpers = helper_lengths["g"],
				control_pars = [ par.name for par in self.control_pars ],
				additive = self.additive,
				numpy_rng = numpy_rng,
				chunk_size = chunk_size, # only for OMP
				callbacks = [(fun.name,n_args) for fun,_,n_args in self.callback_functions],
			)
		
		if not numpy_rng:
			rng_file = path.join(path.dirname(__file__),"random_numbers.c")
			shutil.copy(rng_file,self._tmpfile())
		
		self._compile_and_load(verbose,extra_compile_args,extra_link_args,omp)
コード例 #8
0
ファイル: _jitcsde.py プロジェクト: neurophysik/jitcsde
#!/usr/bin/python3
# -*- coding: utf-8 -*-

from warnings import warn
from itertools import count, chain
from os import path as path
import shutil
import random
import symengine
import numpy as np
from jitcxde_common import jitcxde, checker
from jitcxde_common.helpers import sort_helpers, sympify_helpers, copy_helpers, filter_helpers, find_dependent_helpers
from jitcxde_common.symbolic import collect_arguments, has_function

#: the symbol for the state that must be used to define the differential equation. It is a function and the integer argument denotes the component. You may just as well define an analogous function directly with SymEngine or SymPy, but using this function is the best way to get the most of future versions of JiTCSDE, in particular avoiding incompatibilities. You can import a SymPy variant from the submodule `sympy_symbols` instead (see `SymPy vs. SymEngine`_ for details).
y = symengine.Function("y")

#: the symbol for time for defining the differential equation. If your differential equation has no explicit time dependency (“autonomous system”), you do not need this. You may just as well define an analogous symbol directly with SymEngine or SymPy, but using this function is the best way to get the most of future versions of JiTCSDE, in particular avoiding incompatibilities. You can import a SymPy variant from the submodule `sympy_symbols` instead (see `SymPy vs. SymEngine`_ for details).
t = symengine.Symbol("t",real=True)

class UnsuccessfulIntegration(Exception):
	"""
		This exception is raised when the integrator cannot meet the accuracy and step-size requirements. If you want to know the exact state of your system before the integration fails or similar, catch this exception.
	"""
	pass

class jitcsde(jitcxde):
	"""
	Parameters
	----------
	f_sym : iterable of symbolic expressions or generator function yielding symbolic expressions or dictionary
コード例 #9
0
    def generate_jac_C(self, do_cse=False, chunk_size=100, sparse=True):
        """
		translates the symbolic Jacobian to C code using SymEngine’s `C-code printer <https://github.com/symengine/symengine/pull/1054>`_. 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. Also, this feature uses SymPy and not SymEngine.
		
		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. See `Handling very large differential equations <http://jitcde-common.readthedocs.io/#handling-very-large-differential-equations>`_ on why this is useful and how to best choose this value.
			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 `ode` or `solve_ivp` to be able to handle sparse matrices without structure in the sparseness.
		"""

        self._generate_helpers_C()

        # working copy
        jac_sym_wc = ((entry.subs(self.general_subs) for entry in line)
                      for line in self.jac_sym)
        self.sparse_jac = sparse

        arguments = self._default_arguments()
        if self.helpers:
            arguments.append(
                ("general_helper", "double const *__restrict const"))

        if do_cse:
            import sympy
            get_helper = sympy.Function("get_jac_helper")
            set_helper = symengine.Function("set_jac_helper")
            jac_sym_wc = sympy.Matrix(
                [[sympy.sympify(entry) for entry in line]
                 for line in jac_sym_wc])

            _cse = sympy.cse(sympy.sympify(jac_sym_wc),
                             symbols=(get_helper(i) for i in count()))
            more_helpers = symengine.sympify(_cse[0])
            jac_sym_wc = symengine.sympify(_cse[1][0].tolist())

            if more_helpers:
                arguments.append(("jac_helper", "double *__restrict const"))
                self.render_and_write_code(
                    (set_helper(i, helper[1])
                     for i, helper in enumerate(more_helpers)),
                    name="jac_helpers",
                    chunk_size=chunk_size,
                    arguments=arguments,
                    omp=False)
                self._number_of_jac_helpers = len(more_helpers)

        set_dfdy = symengine.Function("set_dfdy")

        self.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)),
            name="jac",
            chunk_size=chunk_size,
            arguments=arguments +
            [("dfdY", "PyArrayObject *__restrict const")])

        self._jac_C_source = True
コード例 #10
0
    def generate_f_C(self, simplify=None, do_cse=False, chunk_size=100):
        """
		translates the derivative to C code using SymEngine’s `C-code printer <https://github.com/symengine/symengine/pull/1054>`_.
		
		Parameters
		----------
		simplify : boolean or None
			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 enable this is if you expect your derivative not to be optimised and not be so large that simplifying takes a considerable amount of time. If `None`, this will be automatically disabled for `n>10`.
		
		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. Also, this feature uses SymPy and not SymEngine.
		
		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. See `Handling very large differential equations <http://jitcde-common.readthedocs.io/#handling-very-large-differential-equations>`_ on why this is useful and how to best choose this value.
			If smaller than 1, no chunking will happen.
		"""

        self._generate_helpers_C()

        # working copy
        f_sym_wc = (entry.subs(self.general_subs) for entry in self.f_sym())

        if simplify is None:
            simplify = self.n <= 10
        if simplify:
            f_sym_wc = (entry.simplify(ratio=1) for entry in f_sym_wc)

        arguments = self._default_arguments()

        if self.helpers:
            arguments.append(
                ("general_helper", "double const *__restrict const"))

        if do_cse:
            import sympy
            get_helper = sympy.Function("get_f_helper")
            set_helper = symengine.Function("set_f_helper")

            _cse = sympy.cse(sympy.Matrix(sympy.sympify(list(f_sym_wc))),
                             symbols=(get_helper(i) for i in count()))
            more_helpers = symengine.sympify(_cse[0])
            f_sym_wc = symengine.sympify(_cse[1][0])

            if more_helpers:
                arguments.append(("f_helper", "double *__restrict const"))
                self.render_and_write_code(
                    (set_helper(i, helper[1])
                     for i, helper in enumerate(more_helpers)),
                    name="f_helpers",
                    chunk_size=chunk_size,
                    arguments=arguments,
                    omp=False,
                )
                self._number_of_f_helpers = len(more_helpers)

        set_dy = symengine.Function("set_dy")
        self.render_and_write_code(
            (set_dy(i, entry) for i, entry in enumerate(f_sym_wc)),
            name="f",
            chunk_size=chunk_size,
            arguments=arguments + [("dY", "PyArrayObject *__restrict const")])

        self._f_C_source = True
コード例 #11
0
"""
Tests whether things works independent of where symbols are imported from.
"""

import jitcsde
import jitcsde.sympy_symbols
import sympy
import symengine
import random

symengine_manually = [
    symengine.Symbol("t", real=True),
    symengine.Function("y", real=True),
    symengine.cos,
]

sympy_manually = [
    sympy.Symbol("t", real=True),
    sympy.Function("y", real=True),
    sympy.cos,
]

jitcsde_provisions = [
    jitcsde.t,
    jitcsde.y,
    symengine.cos,
]

jitcsde_sympy_provisions = [
    jitcsde.sympy_symbols.t,
    jitcsde.sympy_symbols.y,
コード例 #12
0
ファイル: symengine.py プロジェクト: redrossa/pymbolic
# {{{ pymbolic -> symengine


class PymbolicToSymEngineMapper(PymbolicToSympyLikeMapper):

    sym = symengine

    def raise_conversion_error(self, expr):
        raise RuntimeError("do not know how to translate '%s' to symengine" %
                           expr)


# }}}

CSE = symengine.Function("CSE")


def make_cse(arg, prefix=None, scope=None):
    # SymEngine's classes can't be inherited, but there's a
    # mechanism to create one based on SymPy's ones which stores
    # the SymPy object inside the C++ object.
    # This SymPy object is later retrieved to get the prefix
    # These conversions between SymPy and SymEngine are expensive,
    # so use it only if necessary.
    if prefix is None and scope is None:
        return CSE(arg)
    from pymbolic.interop.sympy import make_cse as make_cse_sympy
    sympy_result = make_cse_sympy(arg, prefix=prefix, scope=scope)
    return symengine.sympify(sympy_result)