def test_nested_functions_diff(): """Examples of differentiation using nested functions. This functionality is built in to Symbolic.prepJacobian """ func_ma_spec = (["p", "v"], "0.32*(v+54)/(1-exp(-p*(v+54)/4))") ma = Fun(func_ma_spec[1], func_ma_spec[0], "ma") ma_1 = Fun(Diff(ma, "v"), ["v"], "ma_1") func_mb_spec = (["v"], "0.28*(v+27)/(exp((v+27)/5)-1)") mb = Fun(func_mb_spec[1], func_ma_spec[0], "mb") mb_0 = Fun(Diff(mb, "v"), ["v"], "mb_0") func_ma_1_spec = (["p", "v"], str(ma_1.spec)) func_mb_0_spec = (["v"], str(mb_0.spec)) # artificial example to introduce time dependence rhs_m = "exp(-2*t)*(100-v) + ma(1, v)*(1-m)-mb(v)*m" jac_part = Diff(rhs_m, ["v", "m"]) f = expr2fun(jac_part, ma_1=func_ma_1_spec, mb_0=func_mb_0_spec, ma=func_ma_spec, mb=func_mb_spec) assert remain(f._args, ["t", "v", "m"]) == [] assert abs(norm(f(0, -50, 0.2)) - 8.565615) < 1e-6 # alternative usage syntax assert abs(norm(f(**{"t": 0, "v": -50, "m": 0.2})) - 8.565615) < 1e-6
def test_nested_functions_diff(): """Examples of differentiation using nested functions. This functionality is built in to Symbolic.prepJacobian """ func_ma_spec = (['p', 'v'], '0.32*(v+54)/(1-exp(-p*(v+54)/4))') ma = Fun(func_ma_spec[1], func_ma_spec[0], 'ma') ma_1 = Fun(Diff(ma, 'v'), ['v'], 'ma_1') func_mb_spec = (['v'], '0.28*(v+27)/(exp((v+27)/5)-1)') mb = Fun(func_mb_spec[1], func_ma_spec[0], 'mb') mb_0 = Fun(Diff(mb, 'v'), ['v'], 'mb_0') func_ma_1_spec = (['p', 'v'], str(ma_1.spec)) func_mb_0_spec = (['v'], str(mb_0.spec)) # artificial example to introduce time dependence rhs_m = 'exp(-2*t)*(100-v) + ma(1, v)*(1-m)-mb(v)*m' jac_part = Diff(rhs_m, ['v', 'm']) f = expr2fun(jac_part, ma_1=func_ma_1_spec, mb_0=func_mb_0_spec, ma=func_ma_spec, mb=func_mb_spec) assert remain(f._args, ['t', 'v', 'm']) == [] assert abs(norm(f(0, -50, 0.2)) - 8.565615) < 1e-6 # alternative usage syntax assert abs(norm(f(**{'t': 0, 'v': -50, 'm': 0.2})) - 8.565615) < 1e-6
def make_Jac(DS, varnames=None): if varnames is None: varnames = DS.funcspec.vars subdomain = {} fixedvars = remain(DS.funcspec.vars, varnames) for k in fixedvars: subdomain[k] = DS.initialconditions[k] jac, new_fnspecs = prepJacobian(DS.funcspec._initargs['varspecs'], varnames, DS.funcspec._initargs['fnspecs']) scope = copy.copy(DS.pars) scope.update(subdomain) scope.update(new_fnspecs) return expr2fun(jac, ensure_args=['t'], **scope)
def test_symbolic(): assert doneg('-x-y') == 'x+y' assert doneg('(-x-y)') == '(x+y)' assert doneg('-(-x-y)') == '(-x-y)' assert dosub('1', '-x-y') == '(1+x+y)' g2 = expr2fun('1-max([0., -a+b*x])', **{'a': 3, 'b': 1.5}) assert g2._args == ['x'] assert g2(1) == 1.0 assert g2(10) == -11.0 ds = {'a': 3, 'bbb': 1} f=expr2fun('1+ds["a"]') assert f._args == ['ds'] assert f(ds) == 4 f2=expr2fun('1+ds["a"]') assert f2(**{'ds':ds}) == 4 assert f2._args == ['ds'] g=expr2fun('1+ds["bbb"]', ds=ds) assert g() == 2 # g must be dynamic and not based on static eval of ds on initialization ds['bbb'] = 2 assert g._args == [] assert g() == 3 m = args(pars=copy(ds)) h = expr2fun('m.pars["a"]+c', m=m, c=1) assert h() == 4 assert h._args == [] h2 = expr2fun('1 + m.pars["a"]/2.', m=m) assert h2() == 2.5 assert h2._args == [] def func(x, y): return x * (y+1) m.func = func i = expr2fun('1+func(x,y)+b', func=m.func, b=0.5) assert 1+func(2,3)+0.5 == i(2,3) j = expr2fun('i(x,func(2,y))*2', i=i, func=m.func) assert j(1,0) == 9 fnspec = {'f': (['x','y'], 'x+1+2*y-a')} # a is expected to be in scope like a FuncSpec parameter # so can't use the above method of providing explicit functions k = expr2fun('-f(c,d)+b', f=fnspec['f'], b=0.5, a=1) assert k(1,2) == -4.5 s='1+a/(f(x,y)-3)+h(2)' t=s.replace('y','g(x,z)') u=t.replace('z','f(z)') r1, d1 = replaceCallsWithDummies(s, ['f','g','h']) r2, d2 = replaceCallsWithDummies(t, ['f','g','h']) r3, d3 = replaceCallsWithDummies(u, ['f','g','h']) assert r1 == '1+a/(__dummy1__-3)+__dummy2__' assert len(d1) == 2 assert r2 == '1+a/(__dummy2__-3)+__dummy3__' assert len(d2) == 3 assert r2 == '1+a/(__dummy2__-3)+__dummy3__' assert len(d3) == 4 ps = 'abs((HB9_fs_Vq-HB9_fs_V)*(-((HB9_fs_Lk_g*(HB9_fs_V-HB9_fs_Lk_vrev))+(-HB9_fs_Iapp_Ibias)+((HB9_fs_Na_g*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1-HB9_fs_K_n))*(HB9_fs_V-HB9_fs_Na_vrev))+(HB9_fs_K_g*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*(HB9_fs_V-HB9_fs_K_vrev))+(HB9_fs_isyn_g*(HB9_fs_V-HB9_fs_isyn_vrev))+(HB9_fs_esyn_g*(HB9_fs_V-HB9_fs_esyn_vrev)))/HB9_fs_C)+(HB9_fs_Knq-HB9_fs_K_n)*(((1.0/(1.0+exp((HB9_fs_V-HB9_fs_K_theta_n)/HB9_fs_K_k_n)))-HB9_fs_K_n)/(HB9_fs_K_taun_bar/cosh((HB9_fs_V-HB9_fs_K_theta_n)/(2*HB9_fs_K_k_n)))))/(sqrt(HB9_fs_Vq*HB9_fs_Vq+HB9_fs_Knq*HB9_fs_Knq)+sqrt(pow((-((HB9_fs_Lk_g*(HB9_fs_V-HB9_fs_Lk_vrev))+(-HB9_fs_Iapp_Ibias)+((HB9_fs_Na_g*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1-HB9_fs_K_n))*(HB9_fs_V-HB9_fs_Na_vrev))+(HB9_fs_K_g*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*(HB9_fs_V-HB9_fs_K_vrev))+(HB9_fs_isyn_g*(HB9_fs_V-HB9_fs_isyn_vrev))+(HB9_fs_esyn_g*(HB9_fs_V-HB9_fs_esyn_vrev)))/HB9_fs_C),2)+pow((((1.0/(1.0+exp((HB9_fs_V-HB9_fs_K_theta_n)/HB9_fs_K_k_n)))-HB9_fs_K_n)/(HB9_fs_K_taun_bar/cosh((HB9_fs_V-HB9_fs_K_theta_n)/(2*HB9_fs_K_k_n)))),2)))' parnames = ['HB9_fs_Vq', 'HB9_fs_Lk_g', 'HB9_fs_Lk_vrev', 'HB9_fs_Iapp_Ibias', 'HB9_fs_Na_g', 'HB9_fs_Na_theta_m', 'HB9_fs_Na_k_m', 'HB9_fs_Na_vrev', 'HB9_fs_K_g', 'HB9_fs_K_vrev', 'HB9_fs_isyn_g', 'HB9_fs_isyn_vrev', 'HB9_fs_esyn_g', 'HB9_fs_esyn_vrev', 'HB9_fs_C', 'HB9_fs_Knq', 'HB9_fs_K_theta_n', 'HB9_fs_K_k_n', 'HB9_fs_K_taun_bar'] varnames = ['HB9_fs_V', 'HB9_fs_K_n'] ps2 = convertPowers(ps, 'pow') for n in parnames+varnames: v=rand(1)[0]+1e-5 ps2=ps2.replace(n,str(v)) ps=ps.replace(n,str(v)) eps=eval(ps) eps2=eval(ps2) assert eps==eps2 a = Par('3.5', 'a') qa = Var(['a*3', 'b'], 'array_test') assert str(qa.eval(a=1)) == '[3,b]' # explicit exporting 'a' to globals to make this work as expected globals()['a'] = a assert str(qa.eval()) == '[10.5,b]' testq = QuantSpec('d', 'a') testq.simplify() assert testq() == 'a' assert str(testq.eval(a=3)) == '3' q = QuantSpec('q', 'zeta(yrel(y,initcond(y)),z)-1') print q.eval({}) assert 'initcond' in str(q.eval({})) q2=QuantSpec('q','Exp(-spikeTable+b)/k') assert 'spikeTable' in q2.freeSymbols # x = Var('x') # print x.isDefined() # xs = QuantSpec('x', '1-rel - 2*x + cos(z) + 2e10', 'RHSfuncSpec') # x.bindSpec(xs) # print x.isDefined(),"\n" x = Var(QuantSpec('x', '1-rel - 2*x + cos(z) + 2e10', 'RHSfuncSpec')) p = Par('p') az = Var(QuantSpec('z', 'myfunc(0,z)+abs(x+1)', 'RHSfuncSpec')) w = Var('x-1/w[i]', 'w[i,0,1]', specType='RHSfuncSpec') myLeaf1.compatibleContainers=(myNode,) myLeaf2.compatibleContainers=(myNode,) myNode.compatibleSubcomponents=(myLeaf1,myLeaf2) c = myLeaf1('leaf1') assert c.isDefined() == False c.add(x) print c.freeSymbols, c.isDefined() c.add(az) print c.freeSymbols, c.isDefined() c.add(w) print c.freeSymbols, c.isDefined() c.compileFuncSpec() print c.funcSpecDict empty_fn = Fun('1+exp(1)', [], 'dumb_fn') print empty_fn() q = Par('qpar') y = Var(QuantSpec('rel', 'v+p'), domain=[0,1]) g = Fun(QuantSpec('qfunc', '-1.e-05+sin(qpar)*(10.e-5-xtol)'), ['xtol']) d = myLeaf2('leaf2') ## d.add(y) q_dummy = Var(QuantSpec('q_notpar', '-2+sin(30)')) g_dummy = Fun(QuantSpec('qfunc_dummy', 'sin(q_notpar)*(10.e-5-xtol)'), ['xtol']) d.add([q_dummy, g_dummy]) # will delete these later d.add([q,g]) d2 = myLeaf2('leaf3') d2.add([q,g]) v = Var(QuantSpec('v', 'v * myfunc(rel,v) - sin(p)*t', 'RHSfuncSpec')) # p is a global parameter so this is ok in v f = Fun(QuantSpec('myfunc', '2.0+s-t+exp(p)'), ['s','t']) # t is just a local argument here, so it won't clash with its # occurrence in v (which we'll see is declared as a global # when we call flattenSpec()). ipar = Par('ipar') z = Var('z[i]+v/(i*ipar)', 'z[i,0,5]', specType='RHSfuncSpec') a = myNode('sys1') a.add([f,p,y]) print a.isDefined(True) a.add(c) print a.freeSymbols, a.isDefined(), a.isComplete() a.add(d) print a.freeSymbols, a.isDefined(), a.isComplete() a.add(d2) print a.freeSymbols, a.isDefined(), a.isComplete() a.add(v) print "Added v" print a.freeSymbols, a.isDefined(), a.isComplete() print "Removed v" a.remove(v) print a.freeSymbols, a.isDefined(), a.isComplete() a.add([z,ipar]) print a.freeSymbols, a.isDefined(), a.isComplete() print "\na._registry --> " print a._registry print "Re-added v" a.add(v) print a.freeSymbols, a.isDefined(), a.isComplete() print "\nv in a -->", v in a print "\n" with pytest.raises(TypeError): a.compileFuncSpec() a.remove(['leaf2.qfunc_dummy', 'leaf2.q_notpar']) print "--------- sys1: funcSpecDict ---------------------" a.compileFuncSpec() info(a.funcSpecDict) print "\n\n------------- Flatten spec with unravelling\n" print "\n\ninfo(a.flattenSpec()) --> \n" info(a.flattenSpec(globalRefs=['t']), "Model specification") print "\n\n------------- Flatten spec with no unravelling\n" print "\n\ninfo(a.flattenSpec(False, globalRefs=['t'])) --> \n" info(a.flattenSpec(False, globalRefs=['t']), "Model specification") print "\n\nDemos for functions (results are strings):\n" h = f(p, -x) z = QuantSpec('zero','0') print "h = f(p, -x) --> ", h print "z = QuantSpec('zero','0') --> ", z print "f(g(3)*1,h) --> ", f(g(3)*1,h) print "f(g(p),h) --> ", f(g(p),h) print "f(g(p),0*h) --> ", f(g(p),0*h) print "f(g(x),h+z) --> ", f(g(x),h+z) # e is the math constant, but it doesn't evaluate to a float! print "f(g(x()),(e+h)/2) --> ", f(g(x()),(e+h)/2) print "f(g(x()),-h) --> ", f(g(x()),-h) print "f(g(x()),.5-h+0) --> ", f(g(x()),.5-h+0) print "Sin(pi+q) --> ", Sin(pi+q) qsin=QuantSpec('qsin','zv-sin(beta)') assert str(qsin.eval()) == 'zv-sin(beta)' print "\n\nDemos for local scope evaluation and **:\n" print "q=Var('xv+1','qv')" print "x=Var('3','xv')" q=Var('xv+1','qv') x=Var('3','xv') globals()['x'] = x globals()['q'] = q sc1 = str(q.eval()) == '4' print "q.eval() == 4? ", sc1 assert sc1 print "a=x/q" a=x/q sc2 = str(a) == 'xv/qv' print "a == xv/qv? ", sc2 assert sc2 sc3 = str(a.eval())=='0.75' print "a.eval() == 0.75? ", sc3 assert sc3 sc4 = str(a.eval(xv=5))=='5/qv' print "a.eval(xv=5) == 5/q? ", sc4 assert sc4 sc5 = (str(a.eval(xv=5,qv=q())),'0.83333333333333337') assert_approx_equal(*sc5) print "assert_approx_equal(%s,%s)" % sc5 sc6 = (str(a.eval({'xv': 10, 'qv': q()})),'0.90909090909090906') print "assert_approx_equal(%s,%s)" % sc6 assert_approx_equal(*sc6) print "qs=QuantSpec('qsv','xsv+1')" print "xs=QuantSpec('xsv','3')" qs=QuantSpec('qsv','xsv+1') xs=QuantSpec('xsv','3') globals()['qs'] = qs globals()['xs'] = xs qse = qs.eval() qt1 = str(qse) == '4' print "qs.eval() == 4? ", qt1 assert qt1 assert qse.tonumeric() == 4 print "asq = xs/qs" asq=xs/qs qt2 = str(asq) == '3/(xsv+1)' print "asq == 3/(xsv+1)? ", qt2 assert qt2 qt3 = str(asq.eval()) == '0.75' print "as.eval() == 0.75? ", qt3 assert qt3 ps = asq**xs print "ps = as**xs" qt4 = str(ps) == 'Pow(3/(xsv+1),3)' print "ps == Pow(3/(xsv+1),3)? ", qt4 assert qt4 qt5 = str(ps.eval()) == str(0.75**3) print "ps.eval() == 0.421875? ", qt5 assert qt5 print "sq=QuantSpec('sv','sin(xsv)')" print "s2q=QuantSpec('s2v','Sin(xv)')" sq=QuantSpec('sv','sin(xsv)') s2q=QuantSpec('s2v','Sin(xv)') print "sq.eval() --> ", sq.eval() print "s2q.eval() --> ", s2q.eval() assert sq.eval().tonumeric() == s2q.eval().tonumeric() assert sq[:] == ['sin','(','xsv',')'] print "\n\nDemos for multiple quantity definitions:\n" mp=QuantSpec('p','a + 3*z[4*i-2]') m=Var(mp, 'z[i,2,5]', specType='RHSfuncSpec') v=Var('3*z[i-1]+z4-i', 'z[i,1,5]', specType='RHSfuncSpec') print "mp=QuantSpec('p','a + 3*z[4*i-2]')" print "m=Var(mp, 'z[i,2,5]', specType='RHSfuncSpec')" print "v=Var('3*z[i-1]+z4-i', 'z[i,1,5]', specType='RHSfuncSpec')" print "v[3] -->", v[3] assert str(v[3])=='z3' print "v.freeSymbols -->", v.freeSymbols assert v.freeSymbols == ['z0'] print "\nModelSpec a already contains 'z0', which was defined as part of" print "a multiple quantity definition, so check that attempting to add" print "v to a results in an error ..." with pytest.raises(AttributeError): a.add(v) print "\nTest of eval method, e.g. on a function f(s,t)..." print "f.eval(s='1', t='t_val') -->", f.eval(s='1', t='t_val') print "f.eval(s=1, t='t_val', p=0.5) -->", f.eval(s=1, t='t_val', p=0.5) print "\nTesting convertPowers():" cp_tests = ["phi1dot^m3", "1+phi1dot^m3*s", "phi1dot**m3", "1+phi1dot**m3*s", "sin(x^3)**4", "(2/3)^2.5", "3^cos(x)-pi", "3^(cos(x)-pi)", "2^(sin(y**p))"] for spec in cp_tests: print spec, " --> ", convertPowers(spec) globals().pop('a') qc=QuantSpec('t', "a+coot+b/'coot'") assert str(qc.eval()) == 'a+coot+b/"coot"' coot=QuantSpec('coot', "1.05") globals()['coot'] = coot assert str(qc.eval()) == 'a+1.05+b/"coot"' print "\nTest of function calling with argument names that clash with" print "bound names inside the function." x0=Var('x0') x1=Var('x1') x2=Var('x2') F=Fun([x0*x2,x0*5,x2**0.5], [x0,x1,x2], 'F') print "F=Fun([x0*x2,x0*5,x2**0.5], [x0,x1,x2], 'F')" print "F(3,2,Sin(x0))) = [3*Sin(x0),15,Pow(Sin(x0),0.5)] ..." print " ... even though x0 is a bound name inside definition of F" assert str(F(3,2,Sin(x0)))=='[3*Sin(x0),15,Pow(Sin(x0),0.5)]'
def test_symbolic(): assert doneg('-x-y') == 'x+y' assert doneg('(-x-y)') == '(x+y)' assert doneg('-(-x-y)') == '(-x-y)' assert dosub('1', '-x-y') == '(1+x+y)' g2 = expr2fun('1-max([0., -a+b*x])', **{'a': 3, 'b': 1.5}) assert g2._args == ['x'] assert g2(1) == 1.0 assert g2(10) == -11.0 ds = {'a': 3, 'bbb': 1} f = expr2fun('1+ds["a"]') assert f._args == ['ds'] assert f(ds) == 4 f2 = expr2fun('1+ds["a"]') assert f2(**{'ds': ds}) == 4 assert f2._args == ['ds'] g = expr2fun('1+ds["bbb"]', ds=ds) assert g() == 2 # g must be dynamic and not based on static eval of ds on initialization ds['bbb'] = 2 assert g._args == [] assert g() == 3 m = args(pars=copy(ds)) h = expr2fun('m.pars["a"]+c', m=m, c=1) assert h() == 4 assert h._args == [] h2 = expr2fun('1 + m.pars["a"]/2.', m=m) assert h2() == 2.5 assert h2._args == [] def func(x, y): return x * (y + 1) m.func = func i = expr2fun('1+func(x,y)+b', func=m.func, b=0.5) assert 1 + func(2, 3) + 0.5 == i(2, 3) j = expr2fun('i(x,func(2,y))*2', i=i, func=m.func) assert j(1, 0) == 9 fnspec = {'f': (['x', 'y'], 'x+1+2*y-a')} # a is expected to be in scope like a FuncSpec parameter # so can't use the above method of providing explicit functions k = expr2fun('-f(c,d)+b', f=fnspec['f'], b=0.5, a=1) assert k(1, 2) == -4.5 s = '1+a/(f(x,y)-3)+h(2)' t = s.replace('y', 'g(x,z)') u = t.replace('z', 'f(z)') r1, d1 = replaceCallsWithDummies(s, ['f', 'g', 'h']) r2, d2 = replaceCallsWithDummies(t, ['f', 'g', 'h']) r3, d3 = replaceCallsWithDummies(u, ['f', 'g', 'h']) assert r1 == '1+a/(__dummy1__-3)+__dummy2__' assert len(d1) == 2 assert r2 == '1+a/(__dummy2__-3)+__dummy3__' assert len(d2) == 3 assert r2 == '1+a/(__dummy2__-3)+__dummy3__' assert len(d3) == 4 ps = 'abs((HB9_fs_Vq-HB9_fs_V)*(-((HB9_fs_Lk_g*(HB9_fs_V-HB9_fs_Lk_vrev))+(-HB9_fs_Iapp_Ibias)+((HB9_fs_Na_g*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1-HB9_fs_K_n))*(HB9_fs_V-HB9_fs_Na_vrev))+(HB9_fs_K_g*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*(HB9_fs_V-HB9_fs_K_vrev))+(HB9_fs_isyn_g*(HB9_fs_V-HB9_fs_isyn_vrev))+(HB9_fs_esyn_g*(HB9_fs_V-HB9_fs_esyn_vrev)))/HB9_fs_C)+(HB9_fs_Knq-HB9_fs_K_n)*(((1.0/(1.0+exp((HB9_fs_V-HB9_fs_K_theta_n)/HB9_fs_K_k_n)))-HB9_fs_K_n)/(HB9_fs_K_taun_bar/cosh((HB9_fs_V-HB9_fs_K_theta_n)/(2*HB9_fs_K_k_n)))))/(sqrt(HB9_fs_Vq*HB9_fs_Vq+HB9_fs_Knq*HB9_fs_Knq)+sqrt(pow((-((HB9_fs_Lk_g*(HB9_fs_V-HB9_fs_Lk_vrev))+(-HB9_fs_Iapp_Ibias)+((HB9_fs_Na_g*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1.0/(1.0+exp((HB9_fs_V-HB9_fs_Na_theta_m)/HB9_fs_Na_k_m)))*(1-HB9_fs_K_n))*(HB9_fs_V-HB9_fs_Na_vrev))+(HB9_fs_K_g*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*HB9_fs_K_n*(HB9_fs_V-HB9_fs_K_vrev))+(HB9_fs_isyn_g*(HB9_fs_V-HB9_fs_isyn_vrev))+(HB9_fs_esyn_g*(HB9_fs_V-HB9_fs_esyn_vrev)))/HB9_fs_C),2)+pow((((1.0/(1.0+exp((HB9_fs_V-HB9_fs_K_theta_n)/HB9_fs_K_k_n)))-HB9_fs_K_n)/(HB9_fs_K_taun_bar/cosh((HB9_fs_V-HB9_fs_K_theta_n)/(2*HB9_fs_K_k_n)))),2)))' parnames = [ 'HB9_fs_Vq', 'HB9_fs_Lk_g', 'HB9_fs_Lk_vrev', 'HB9_fs_Iapp_Ibias', 'HB9_fs_Na_g', 'HB9_fs_Na_theta_m', 'HB9_fs_Na_k_m', 'HB9_fs_Na_vrev', 'HB9_fs_K_g', 'HB9_fs_K_vrev', 'HB9_fs_isyn_g', 'HB9_fs_isyn_vrev', 'HB9_fs_esyn_g', 'HB9_fs_esyn_vrev', 'HB9_fs_C', 'HB9_fs_Knq', 'HB9_fs_K_theta_n', 'HB9_fs_K_k_n', 'HB9_fs_K_taun_bar' ] varnames = ['HB9_fs_V', 'HB9_fs_K_n'] ps2 = convertPowers(ps, 'pow') for n in parnames + varnames: v = rand(1)[0] + 1e-5 ps2 = ps2.replace(n, str(v)) ps = ps.replace(n, str(v)) eps = eval(ps) eps2 = eval(ps2) assert eps == eps2 a = Par('3.5', 'a') qa = Var(['a*3', 'b'], 'array_test') assert str(qa.eval(a=1)) == '[3,b]' # explicit exporting 'a' to globals to make this work as expected globals()['a'] = a assert str(qa.eval()) == '[10.5,b]' testq = QuantSpec('d', 'a') testq.simplify() assert testq() == 'a' assert str(testq.eval(a=3)) == '3' q = QuantSpec('q', 'zeta(yrel(y,initcond(y)),z)-1') print(q.eval({})) assert 'initcond' in str(q.eval({})) q2 = QuantSpec('q', 'Exp(-spikeTable+b)/k') assert 'spikeTable' in q2.freeSymbols # x = Var('x') # print x.isDefined() # xs = QuantSpec('x', '1-rel - 2*x + cos(z) + 2e10', 'RHSfuncSpec') # x.bindSpec(xs) # print x.isDefined(),"\n" x = Var(QuantSpec('x', '1-rel - 2*x + cos(z) + 2e10', 'RHSfuncSpec')) p = Par('p') az = Var(QuantSpec('z', 'myfunc(0,z)+abs(x+1)', 'RHSfuncSpec')) w = Var('x-1/w[i]', 'w[i,0,1]', specType='RHSfuncSpec') myLeaf1.compatibleContainers = (myNode, ) myLeaf2.compatibleContainers = (myNode, ) myNode.compatibleSubcomponents = (myLeaf1, myLeaf2) c = myLeaf1('leaf1') assert c.isDefined() == False c.add(x) print(c.freeSymbols, c.isDefined()) c.add(az) print(c.freeSymbols, c.isDefined()) c.add(w) print(c.freeSymbols, c.isDefined()) c.compileFuncSpec() print(c.funcSpecDict) empty_fn = Fun('1+exp(1)', [], 'dumb_fn') print(empty_fn()) q = Par('qpar') y = Var(QuantSpec('rel', 'v+p'), domain=[0, 1]) g = Fun(QuantSpec('qfunc', '-1.e-05+sin(qpar)*(10.e-5-xtol)'), ['xtol']) d = myLeaf2('leaf2') ## d.add(y) q_dummy = Var(QuantSpec('q_notpar', '-2+sin(30)')) g_dummy = Fun(QuantSpec('qfunc_dummy', 'sin(q_notpar)*(10.e-5-xtol)'), ['xtol']) d.add([q_dummy, g_dummy]) # will delete these later d.add([q, g]) d2 = myLeaf2('leaf3') d2.add([q, g]) v = Var(QuantSpec('v', 'v * myfunc(rel,v) - sin(p)*t', 'RHSfuncSpec')) # p is a global parameter so this is ok in v f = Fun(QuantSpec('myfunc', '2.0+s-t+exp(p)'), ['s', 't']) # t is just a local argument here, so it won't clash with its # occurrence in v (which we'll see is declared as a global # when we call flattenSpec()). ipar = Par('ipar') z = Var('z[i]+v/(i*ipar)', 'z[i,0,5]', specType='RHSfuncSpec') a = myNode('sys1') a.add([f, p, y]) print(a.isDefined(True)) a.add(c) print(a.freeSymbols, a.isDefined(), a.isComplete()) a.add(d) print(a.freeSymbols, a.isDefined(), a.isComplete()) a.add(d2) print(a.freeSymbols, a.isDefined(), a.isComplete()) a.add(v) print("Added v") print(a.freeSymbols, a.isDefined(), a.isComplete()) print("Removed v") a.remove(v) print(a.freeSymbols, a.isDefined(), a.isComplete()) a.add([z, ipar]) print(a.freeSymbols, a.isDefined(), a.isComplete()) print("\na._registry --> ") print(a._registry) print("Re-added v") a.add(v) print(a.freeSymbols, a.isDefined(), a.isComplete()) print("\nv in a -->", v in a) print("\n") with pytest.raises(TypeError): a.compileFuncSpec() a.remove(['leaf2.qfunc_dummy', 'leaf2.q_notpar']) print("--------- sys1: funcSpecDict ---------------------") a.compileFuncSpec() info(a.funcSpecDict) print("\n\n------------- Flatten spec with unravelling\n") print("\n\ninfo(a.flattenSpec()) --> \n") info(a.flattenSpec(globalRefs=['t']), "Model specification") print("\n\n------------- Flatten spec with no unravelling\n") print("\n\ninfo(a.flattenSpec(False, globalRefs=['t'])) --> \n") info(a.flattenSpec(False, globalRefs=['t']), "Model specification") print("\n\nDemos for functions (results are strings):\n") h = f(p, -x) z = QuantSpec('zero', '0') print("h = f(p, -x) --> ", h) print("z = QuantSpec('zero','0') --> ", z) print("f(g(3)*1,h) --> ", f(g(3) * 1, h)) print("f(g(p),h) --> ", f(g(p), h)) print("f(g(p),0*h) --> ", f(g(p), 0 * h)) print("f(g(x),h+z) --> ", f(g(x), h + z)) # e is the math constant, but it doesn't evaluate to a float! print("f(g(x()),(e+h)/2) --> ", f(g(x()), (e + h) / 2)) print("f(g(x()),-h) --> ", f(g(x()), -h)) print("f(g(x()),.5-h+0) --> ", f(g(x()), .5 - h + 0)) print("Sin(pi+q) --> ", Sin(pi + q)) qsin = QuantSpec('qsin', 'zv-sin(beta)') assert str(qsin.eval()) == 'zv-sin(beta)' print("\n\nDemos for local scope evaluation and **:\n") print("q=Var('xv+1','qv')") print("x=Var('3','xv')") q = Var('xv+1', 'qv') x = Var('3', 'xv') globals()['x'] = x globals()['q'] = q sc1 = str(q.eval()) == '4' print("q.eval() == 4? ", sc1) assert sc1 print("a=x/q") a = x / q sc2 = str(a) == 'xv/qv' print("a == xv/qv? ", sc2) assert sc2 sc3 = str(a.eval()) == '0.75' print("a.eval() == 0.75? ", sc3) assert sc3 sc4 = str(a.eval(xv=5)) == '5/qv' print("a.eval(xv=5) == 5/q? ", sc4) assert sc4 sc5 = (str(a.eval(xv=5, qv=q())), '0.83333333333333337') assert_approx_equal(*sc5) print("assert_approx_equal(%s,%s)" % sc5) sc6 = (str(a.eval({'xv': 10, 'qv': q()})), '0.90909090909090906') print("assert_approx_equal(%s,%s)" % sc6) assert_approx_equal(*sc6) print("qs=QuantSpec('qsv','xsv+1')") print("xs=QuantSpec('xsv','3')") qs = QuantSpec('qsv', 'xsv+1') xs = QuantSpec('xsv', '3') globals()['qs'] = qs globals()['xs'] = xs qse = qs.eval() qt1 = str(qse) == '4' print("qs.eval() == 4? ", qt1) assert qt1 assert qse.tonumeric() == 4 print("asq = xs/qs") asq = xs / qs qt2 = str(asq) == '3/(xsv+1)' print("asq == 3/(xsv+1)? ", qt2) assert qt2 qt3 = str(asq.eval()) == '0.75' print("as.eval() == 0.75? ", qt3) assert qt3 ps = asq**xs print("ps = as**xs") qt4 = str(ps) == 'Pow(3/(xsv+1),3)' print("ps == Pow(3/(xsv+1),3)? ", qt4) assert qt4 qt5 = str(ps.eval()) == str(0.75**3) print("ps.eval() == 0.421875? ", qt5) assert qt5 print("sq=QuantSpec('sv','sin(xsv)')") print("s2q=QuantSpec('s2v','Sin(xv)')") sq = QuantSpec('sv', 'sin(xsv)') s2q = QuantSpec('s2v', 'Sin(xv)') print("sq.eval() --> ", sq.eval()) print("s2q.eval() --> ", s2q.eval()) assert sq.eval().tonumeric() == s2q.eval().tonumeric() assert sq[:] == ['sin', '(', 'xsv', ')'] print("\n\nDemos for multiple quantity definitions:\n") mp = QuantSpec('p', 'a + 3*z[4*i-2]') m = Var(mp, 'z[i,2,5]', specType='RHSfuncSpec') v = Var('3*z[i-1]+z4-i', 'z[i,1,5]', specType='RHSfuncSpec') print("mp=QuantSpec('p','a + 3*z[4*i-2]')") print("m=Var(mp, 'z[i,2,5]', specType='RHSfuncSpec')") print("v=Var('3*z[i-1]+z4-i', 'z[i,1,5]', specType='RHSfuncSpec')") print("v[3] -->", v[3]) assert str(v[3]) == 'z3' print("v.freeSymbols -->", v.freeSymbols) assert v.freeSymbols == ['z0'] print("\nModelSpec a already contains 'z0', which was defined as part of") print("a multiple quantity definition, so check that attempting to add") print("v to a results in an error ...") with pytest.raises(AttributeError): a.add(v) print("\nTest of eval method, e.g. on a function f(s,t)...") print("f.eval(s='1', t='t_val') -->", f.eval(s='1', t='t_val')) print("f.eval(s=1, t='t_val', p=0.5) -->", f.eval(s=1, t='t_val', p=0.5)) print("\nTesting convertPowers():") cp_tests = [ "phi1dot^m3", "1+phi1dot^m3*s", "phi1dot**m3", "1+phi1dot**m3*s", "sin(x^3)**4", "(2/3)^2.5", "3^cos(x)-pi", "3^(cos(x)-pi)", "2^(sin(y**p))" ] for spec in cp_tests: print(spec, " --> ", convertPowers(spec)) globals().pop('a') qc = QuantSpec('t', "a+coot+b/'coot'") assert str(qc.eval()) == 'a+coot+b/"coot"' coot = QuantSpec('coot', "1.05") globals()['coot'] = coot assert str(qc.eval()) == 'a+1.05+b/"coot"' print("\nTest of function calling with argument names that clash with") print("bound names inside the function.") x0 = Var('x0') x1 = Var('x1') x2 = Var('x2') F = Fun([x0 * x2, x0 * 5, x2**0.5], [x0, x1, x2], 'F') print("F=Fun([x0*x2,x0*5,x2**0.5], [x0,x1,x2], 'F')") print("F(3,2,Sin(x0))) = [3*Sin(x0),15,Pow(Sin(x0),0.5)] ...") print(" ... even though x0 is a bound name inside definition of F") assert str(F(3, 2, Sin(x0))) == '[3*Sin(x0),15,Pow(Sin(x0),0.5)]'