def __init__(self, settings, args, times_to_use): par = Params() self.times_to_use = times_to_use self.starting_parameters = [2.26E-04, 0.0699, 3.45E-05, 0.05462, 0.0873, 8.92E-03, 5.150E-3, 0.03158, 0.1524] # Create symbols for symbolic functions p, y, v = CreateSymbols(settings) # Choose starting parameters (from J Physiol paper) para = [2.26E-04, 0.0699, 3.45E-05, 0.05462, 0.0873, 8.92E-03, 5.150E-3, 0.03158, 0.1524] # Create symbols for symbolic functions p, y, v = CreateSymbols(par) # Define system equations and initial conditions k1 = p[0] * se.exp(p[1] * v) k2 = p[2] * se.exp(-p[3] * v) k3 = p[4] * se.exp(p[5] * v) k4 = p[6] * se.exp(-p[7] * v) # Write in matrix form taking y = ([C], [O], [I])^T A = se.Matrix([[-k1 - k3 - k4, k2 - k4, -k4], [k1, -k2 - k3, k4], [-k1, k3 - k1, -k2 - k4 - k1]]) B = se.Matrix([k4, 0, k1]) rhs = np.array(A * y + B) self.funcs = GetSensitivityEquations(par, p, y, v, A, B, para, times_to_use, sine_wave=args.sine_wave)
def exp(expr): """Exponential""" if type(expr) == GC: return GC( se.exp(expr.expr), {s: d * se.exp(expr.expr) for s, d in expr.gradients.items()}) return se.exp(expr)
def hermite(self, x=Symbol('x'), n=1): expr1_hermite = Symbol('x') expr2_hermite = (-1)**n expr3_hermite = exp(0.5 * expr1_hermite**2) expr4_hermite = diff(exp(-0.5 * expr1_hermite**2), expr1_hermite, n) expr5_hermite = self.simplify(expr2_hermite * expr3_hermite * expr4_hermite) return expr5_hermite.subs([(expr1_hermite, x)])
def test_substitute_helpers(self): backend = NumbaBackend() a = se.Symbol("a") b = se.Symbol("b") y = se.Symbol("y") HELPERS = [(a, se.exp(-12 * y))] DERIVATIVES = [-b * a + y, y**2] result = backend._substitute_helpers(DERIVATIVES, HELPERS) self.assertListEqual(result, [-b * se.exp(-12 * y) + y, y**2])
def _radial(self, x, y, z, alphas, cs, rs=None, pre=None): """Generates the symbolic radial portion of a basis function. Substitutes symbolic (_i) -> (_i - iA) for i in [x, y, z].""" if pre is not None: return sum((pre * self._expnt ** r * c * exp(-a * self._expnt) for c, a, r in zip(cs, alphas, rs)) ).subs({_x: _x - x, _y: _y - y, _z: _z - z}) return sum((c * exp(-a * self._expnt) for c, a in zip(cs, alphas)) ).subs({_x: _x - x, _y: _y - y, _z: _z - z})
def test_sens_limits(): par = Params() p, y, v = CreateSymbols(par) reversal_potential = par.Erev para = np.array([ 2.07, 7.17E1, 3.44E-2, 6.18E1, 4.18E2, 2.58E1, 4.75E1, 2.51E1, 3.33E1 ]) para = para * 1E-3 # Define system equations and initial conditions k1 = p[0] * se.exp(p[1] * v) k2 = p[2] * se.exp(-p[3] * v) k3 = p[4] * se.exp(p[5] * v) k4 = p[6] * se.exp(-p[7] * v) current_limit = (p[-1] * (par.holding_potential - reversal_potential) * k1 / (k1 + k2) * k4 / (k3 + k4)).subs( v, par.holding_potential) print("{} Current limit computed as {}".format( __file__, current_limit.subs(p, para).evalf())) sens_inf = [ float(se.diff(current_limit, p[j]).subs(p, para).evalf()) for j in range(0, par.n_params) ] print("{} sens_inf calculated as {}".format(__file__, sens_inf)) k = se.symbols('k1, k2, k3, k4') # Notation is consistent between the two papers A = se.Matrix([[-k1 - k3 - k4, k2 - k4, -k4], [k1, -k2 - k3, k4], [-k1, k3 - k1, -k2 - k4 - k1]]) B = se.Matrix([k4, 0, k1]) # Use results from HH equations current_limit = (p[-1] * (par.holding_potential - reversal_potential) * k1 / (k1 + k2) * k4 / (k3 + k4)).subs( v, par.holding_potential) funcs = GetSensitivityEquations(par, p, y, v, A, B, para, [0]) sens_inf = [ float(se.diff(current_limit, p[j]).subs(p, para).evalf()) for j in range(0, par.n_params) ] sens = funcs.SimulateForwardModelSensitivities(para)[1] # Check sens = sens_inf error = np.abs(sens_inf - sens) equal = np.all(error < 1e-10) assert (equal) return
def test_exp(): x = Symbol("x") e1 = sympy.exp(sympy.Symbol("x")) e2 = exp(x) assert sympify(e1) == e2 assert e1 == e2._sympy_() e1 = sympy.exp(sympy.Symbol("x")).diff(sympy.Symbol("x")) e2 = exp(x).diff(x) assert sympify(e1) == e2 assert e1 == e2._sympy_()
def __init__(self, settings, args, times_to_use): par = Params() self.times_to_use = times_to_use self.starting_parameters = [ 2.26E-04, 0.0699, 3.45E-05, 0.05462, 0.0873, 8.92E-03, 5.150E-3, 0.03158, 0.1524 ] # Create symbols for symbolic functions p, y, v = CreateSymbols(settings) # Choose starting parameters (from J Physiol paper) para = [ 2.26E-04, 0.0699, 3.45E-05, 0.05462, 0.0873, 8.92E-03, 5.150E-3, 0.03158, 0.1524 ] # Define system equations and initial conditions k1 = p[0] * se.exp(p[1] * v) k2 = p[2] * se.exp(-p[3] * v) k3 = p[4] * se.exp(p[5] * v) k4 = p[6] * se.exp(-p[7] * v) # Write in matrix form taking y = ([C], [O], [I])^T A = se.Matrix([[-k1 - k3 - k4, k2 - k4, -k4], [k1, -k2 - k3, k4], [-k1, k3 - k1, -k2 - k4 - k1]]) B = se.Matrix([k4, 0, k1]) rhs = np.array(A * y + B) protocol = pd.read_csv( os.path.join( os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "protocols", "protocol-staircaseramp.csv")) times = 10000 * protocol["time"].values voltages = protocol["voltage"].values staircase_protocol = scipy.interpolate.interp1d(times, voltages, kind="linear") staircase_protocol_safe = lambda t: staircase_protocol(t) if t < times[ -1] else par.holding_potential self.funcs = GetSensitivityEquations(par, p, y, v, A, B, para, times_to_use, voltage=staircase_protocol_safe)
def test_exp(self): f_1 = lambda time: [np.exp(time),0.5*np.exp(2*time)] f_2 = [symengine.exp(t),symengine.exp(2*t)/2] results = [] for function in (f_1,f_2): self.DDE.purge_past() self.DDE.past_from_function(function) self.DDE.step_on_discontinuities() times = np.arange( self.DDE.t, self.DDE.t+1000, 10 ) result = np.vstack( self.DDE.integrate(time) for time in times ) results.append(result) assert_allclose(results[0],results[1],atol=0.01,rtol=1e-5)
def test_scipy(): from scipy import integrate import numpy as np args = t, x = se.symbols('t, x') lmb = se.Lambdify(args, [se.exp(-x * t) / t**5], as_scipy=True) res = integrate.nquad(lmb, [[1, np.inf], [0, np.inf]]) assert abs(res[0] - 0.2) < 1e-7
def evaluate_expr(expr, xs, ys, zs, arr=None, alpha=None): """Evaluate symbolic expression on a numerical grid. Args: expr (symbolic): sympy or symengine expression xs (np.ndarray): 1D-array of x values ys (np.ndarray): 1D-array of y values zs (np.ndarray): 1D-array of z values arr (np.ndarray): additional 1D-array to multiply expression by alpha (float): multiply expression by gaussian with exponent alpha Note: See :meth:`exatomic.algorithms.orbital_util.numerical_grid_from_field_params` for grid construction details. """ subs = {_x: 'xs', _y: 'ys', _z: 'zs'} # Multiply with an additional array (angular term) if arr is not None: return evaluate('arr * ({})'.format(str(expr.subs(subs)))) # Multiply by an exponential decay factor if alpha is not None: expr = str((expr * exp(-alpha * _r**2)).subs(subs)) return evaluate(expr) # Just evaluate the expression numerically return evaluate(str(expr.subs(subs)))
def evaluate_expr(expr, xs, ys, zs, arr=None, alpha=None): """Evaluate symbolic expression on a numerical grid. Args: expr (symbolic): sympy or symengine expression xs (np.ndarray): 1D-array of x values ys (np.ndarray): 1D-array of y values zs (np.ndarray): 1D-array of z values arr (np.ndarray): additional 1D-array to multiply expression by alpha (float): multiply expression by gaussian with exponent alpha Note: See :meth:`exatomic.algorithms.orbital_util.numerical_grid_from_field_params` for grid construction details. """ subs = {_x: 'xs', _y: 'ys', _z: 'zs'} # Multiply with an additional array (angular term) if arr is not None: return evaluate('arr * ({})'.format(str(expr.subs(subs)))) # Multiply by an exponential decay factor if alpha is not None: expr = str((expr * exp(-alpha * _r ** 2)).subs(subs)) return evaluate(expr) # Just evaluate the expression numerically return evaluate(str(expr.subs(subs)))
def _get_array(): X, Y, Z = inp = array.array('d', [1, 2, 3]) args = x, y, z = se.symbols('x y z') exprs = [x+y+z, se.sin(x)*se.log(y)*se.exp(z)] ref = [X+Y+Z, math.sin(X)*math.log(Y)*math.exp(Z)] def check(arr): assert all([abs(x1-x2) < 1e-13 for x1, x2 in zip(ref, arr)]) return args, exprs, inp, check
def _lifted_gaussian( t: sym.Symbol, center: Union[sym.Symbol, sym.Expr, complex], t_zero: Union[sym.Symbol, sym.Expr, complex], sigma: Union[sym.Symbol, sym.Expr, complex], ) -> sym.Expr: r"""Helper function that returns a lifted Gaussian symbolic equation. For :math:`\sigma=` ``sigma`` the symbolic equation will be .. math:: f(x) = \exp\left(-\frac12 \left(\frac{x - \mu}{\sigma}\right)^2 \right), with the center :math:`\mu=` ``duration/2``. Then, each output sample :math:`y` is modified according to: .. math:: y \mapsto \frac{y-y^*}{1.0-y^*}, where :math:`y^*` is the value of the un-normalized Gaussian at the endpoints of the pulse. This sets the endpoints to :math:`0` while preserving the amplitude at the center, i.e. :math:`y` is set to :math:`1.0`. Args: t: Symbol object representing time. center: Symbol or expression representing the middle point of the samples. t_zero: The value of t at which the pulse is lowered to 0. sigma: Symbol or expression representing Gaussian sigma. Returns: Symbolic equation. """ # Sympy automatically does expand. # This causes expression inconsistency after qpy round-trip serializing through sympy. # See issue for details: https://github.com/symengine/symengine.py/issues/409 t_shifted = (t - center).expand() t_offset = (t_zero - center).expand() gauss = sym.exp(-((t_shifted / sigma) ** 2) / 2) offset = sym.exp(-((t_offset / sigma) ** 2) / 2) return (gauss - offset) / (1 - offset)
def _radial(self, x, y, z, alphas, cs, rs=None, pre=None): """Generates the symbolic radial portion of a basis function. Substitutes symbolic (_i) -> (_i - iA) for i in [x, y, z].""" if pre is not None: return sum((pre * self._expnt**r * c * exp(-a * self._expnt) for c, a, r in zip(cs, alphas, rs))).subs({ _x: _x - x, _y: _y - y, _z: _z - z }) return sum( (c * exp(-a * self._expnt) for c, a in zip(cs, alphas))).subs({ _x: _x - x, _y: _y - y, _z: _z - z })
def test_symengine(arr, sig3): """Test symengine.""" try: import symengine as sge x, y, z = sge.var("x y z") fn = sge.acos(x)/y + sge.exp(-z) func = numbafy(fn, (x, y, z), compiler="vectorize", signatures=sig3) result = func(arr, arr, arr) check = np.arccos(arr)/arr + np.exp(-arr) assert np.allclose(result, check) == True except ImportError: pass
def test_symengine(arr, sig3): """Test symengine.""" try: import symengine as sge x, y, z = sge.var("x y z") fn = sge.acos(x) / y + sge.exp(-z) func = numbafy(fn, (x, y, z), compiler="vectorize", signatures=sig3) result = func(arr, arr, arr) check = np.arccos(arr) / arr + np.exp(-arr) assert np.allclose(result, check) == True except ImportError: pass
def _hermite_gaussians(lmax): """Symbolic hermite gaussians up to order lmax. Args: lmax (int): highest order angular momentum quantum number """ order = 2 * lmax + 1 hgs = OrderedDict() der = exp(-_x**2) for t in range(order): if t: der = der.diff(_x) hgs[t] = (-1)**t * der return hgs
def projector(self): mat = np.zeros((4, 4), dtype=object) for n in range(1, self.N + 1): Koef = self.Rho_Liste[n - 1] * si.exp( -I * self.w_Liste[n - 1] * t[0]) Term11 = self.TensorProduct( self.preMatrixPlus(self.K_Liste[n - 1]), self.integralKernelPlus(n)) Term21 = self.TensorProduct( self.preMatrixMinus(self.K_Liste[n - 1]), self.integralKernelMinus(n)) mat += Koef * (Term11 + Term21) return mat
def _hermite_gaussians(lmax): """Symbolic hermite gaussians up to order lmax. Args: lmax (int): highest order angular momentum quantum number """ order = 2 * lmax + 1 hgs = OrderedDict() der = exp(-_x ** 2) for t in range(order): if t: der = der.diff(_x) hgs[t] = (-1) ** t * der return hgs
def LLF_sym(self, hazard, covariate_data): # x = b, b1, b2, b2 = symengine.symbols('b b1 b2 b3') x = symengine.symbols(f'x:{self.numSymbols}') second = [] prodlist = [] for i in range(self.n): sum1 = 1 sum2 = 1 TempTerm1 = 1 for j in range(self.numParameters, self.numSymbols): TempTerm1 = TempTerm1 * symengine.exp( covariate_data[j - self.numParameters][i] * x[j]) sum1 = 1 - ((1 - (hazard(i + 1, x[:self.numParameters])))**(TempTerm1)) for k in range(i): TempTerm2 = 1 for j in range(self.numParameters, self.numSymbols): TempTerm2 = TempTerm2 * symengine.exp( covariate_data[j - self.numParameters][k] * x[j]) sum2 = sum2 * ( (1 - (hazard(i + 1, x[:self.numParameters])))**(TempTerm2)) second.append(sum2) prodlist.append(sum1 * sum2) firstTerm = -sum(self.failures) #Verified secondTerm = sum(self.failures) * symengine.log( sum(self.failures) / sum(prodlist)) logTerm = [] #Verified for i in range(self.n): logTerm.append(self.failures[i] * symengine.log(prodlist[i])) thirdTerm = sum(logTerm) factTerm = [] #Verified for i in range(self.n): factTerm.append(symengine.log(math.factorial(self.failures[i]))) fourthTerm = sum(factTerm) f = firstTerm + secondTerm + thirdTerm - fourthTerm return f, x
def _HEXP_(node, S1, S2): f = node.children[0].f_expression errList1 = [node.f_expression] + \ [seng.expand(Si*node.f_expression) for Si in S1] errList2 = [seng.expand(Si * node.f_expression) for Si in S2] ferr = sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2]) + node.f_expression herr = sum([ seng.Abs(Si * Sj * seng.exp(ferr)) for Si in S1 + S2 for Sj in S1 + S2 ]) return _solve_(node, errList1, errList2, herr)
def setUp(self): interval = (-3, 2) self.times = np.linspace(*interval, 10) t = symengine.Symbol("t") self.sin_spline = CubicHermiteSpline(n=1) self.sin_spline.from_function( [symengine.sin(t)], times_of_interest=interval, max_anchors=100, ) self.sin_evaluation = self.sin_spline.get_state(self.times) self.exp_spline = CubicHermiteSpline(n=1) self.exp_spline.from_function( [symengine.exp(t)], times_of_interest=interval, max_anchors=100, ) self.exp_evaluation = self.exp_spline.get_state(self.times)
def solve_chi_saddlepoint(mu, Sigma): """Compute the saddlepoint approximation for the generalized chi square distribution given a mean and a covariance matrix. Currently has two different ways of solving: 1. If the mean is close to zero, the system can be solved symbolically.""" P = None eigenvalues, eigenvectors = np.linalg.eig(Sigma) if (eigenvectors == np.diag(eigenvalues)).all(): P = np.eye(len(mu)) else: P = eigenvectors.T Sigma_12 = np.linalg.cholesky(Sigma) b = P @ Sigma_12 @ mu x = sym.Symbol("x") t = sym.Symbol("t") # Cumulant function K = 0 for i, l in enumerate(eigenvalues): K += (t * b[i]**2 * l) / (1 - 2 * t * l) - 1 / 2 * sym.log(1 - 2 * l * t) Kp = sym.diff(K, t).simplify() Kpp = sym.diff(K, t, t).simplify() roots = sym.lib.symengine_wrapper.solve(sym.Eq(Kp, x), t).args if len(roots) > 1: for expr in roots: trial = Kpp.subs(t, expr).subs(x, np.dot(b, b)) if trial >= 0.0: s_hat = expr else: s_hat = roots[0] f = 1 / sym.sqrt(2 * sym.pi * Kpp.subs( t, s_hat)) * sym.exp(K.subs(t, s_hat) - s_hat * x) fp = sym.Lambdify(x, f.simplify()) c = integrate.quad(fp, 0, np.inf)[0] return lambda x: 1 / c * fp(x)
def E(self, t=Symbol('t', positive=True)): expr1_E = self.integrate(self.kappa(self.u), (self.u, 0, t)) return exp(expr1_E)
def _tau_m_h(self, voltage): return 20.0 + 1000.0 / (exp( (voltage + 71.5) / 14.2) + exp(-(voltage + 89.0) / 11.6))
def _m_inf_T(self, voltage): return 1.0 / (1.0 + exp(-(voltage + 52.0) / 7.4))
def _h_inf_T(self, voltage): return 1.0 / (1.0 + exp((voltage + 80.0) / 5.0))
def _tau_h_T(self, voltage): return (85.0 + 1.0 / (exp( (voltage + 48.0) / 4.0) + exp(-(voltage + 407.0) / 50.0)) ) / 3.7371928
def n(self, x=Symbol('x'), Sigma=1): return 1 / sqrt(2 * pi * Sigma) * exp(-0.5 * x**2 / Sigma)
def _m_inf_h(self, voltage): return 1.0 / (1.0 + exp((voltage + 75.0) / 5.5))
def _get_firing_rate(self, voltage): return self.params["Q_max"] / ( 1.0 + exp(-self.params["C1"] * (voltage - self.params["theta"]) / self.params["sigma"]))
def F(self, t=Symbol('t', positive=True)): expr1_F = self.integrate(self.r(self.u), (self.u, 0, t)) return self.s0 * exp(expr1_F)
def _tau_h_T(self, voltage): return (30.8 + (211.4 + exp((voltage + 115.2) / 5.0)) / (1.0 + exp( (voltage + 86.0) / 3.2))) / 3.7371928
def _m_inf_T(self, voltage): return 1.0 / (1.0 + exp(-(voltage + 59.0) / 6.2))