def test_complex(): t = Var('t') s = Var('s') assert str(Diff(Pow((t * 5), 2), t)) != '0' # XXX: doesn't work without global global p p = Par('3.', 'p') f = Fun(QuantSpec('f', str(2.0 + s - 10 * (t ** 2) + Exp(p))), ['s', 't']) assert str(2 * f.eval(s=3, t=t)) == '2*((2.0+3)-10*Pow(t,2)+Exp(p))' assert str(Diff('-10*Pow(t,2)', 't')) == '-20*t' assert str(Diff(2 * f.eval(s=3, t=t), t)) == '2*-20*t' assert str(Diff(3 + t * f.eval(s=3, t=t), t)) == '((2.0+3)-10*Pow(t,2)+Exp(p))+t*(-10*2*t)' assert str(Diff(3 + t * f(s, t), t).eval(s=3, t=1, p=p)) == '((2.0+3)-10*Pow(1,2)+Exp(p))+1*(-10*2*1)' # FIXME: segmentation fault! # assert_almost_equal(Diff(3 + t * f(s, t), t).eval(s=3, # t=1, # p=p()), # -4.914463076812332) assert Diff(str(f(s, t)), 't') == Diff(f(s, t), t) q1 = Diff(f(s, t), t) q2 = Diff(str(f(s, t)), t) assert q1 == q2 assert str(Diff(f(t, s), t)) == '1' assert str(Diff(2 * f(3, t * 5), t)) == '2*-100*t*5' assert str(Diff(2 * f(3, t * 5), t)) != str(0) assert f(s, t) != f(t, s) assert str(f(s, t).eval()) == '(2.0+s)-10*Pow(t,2)+Exp(3.0)' q = f(s, t) assert str(q.eval()) == '(2.0+s)-10*Pow(t,2)+Exp(3.0)' assert str(Diff('g(s)', s)) == 'g_0(s)' assert str(Diff('g(s)', s).eval()) == 'g_0(s)' # XXX: doesn't work without global global dg_dt dg_dt = Fun(QuantSpec('g_0', '2-Sin(t/2)'), ['t']) assert str(Diff('g(t)', t).eval()) == '2-Sin(t/2)' assert str(Diff('g(s)', s)) == 'g_0(s)' assert str(Diff('g(s)', s).eval()) == '2-Sin(s/2)' g = Fun('', [t], 'g') # declare empty function assert str(g(t)) == 'g(t)' assert str(Diff(g(s), s).eval()) == '2-Sin(s/2)' assert eval(str(Diff('pow(1,2)*t', 't'))) == 1 assert eval(str(Diff(Pow(1, 2) * t, t))) == 1 assert str(Diff(Sin(Pow(t, 1)), t)) == 'Cos(t)' q = QuantSpec('q', '-0+3+pow(g(x)*h(y,x),1)*1') assert str(Diff(q, 'x')) == '(g_0(x)*h(y,x)+g(x)*h_1(y,x))'
def test_diff_point_3D(): x0 = Var('x0') x1 = Var('x1') x2 = Var('x2') f5_x0 = Fun(x0 * x2, [x0, x1, x2], 'f5_x0') f5_x1 = Fun(x0 * 5, [x0, x1, x2], 'f5_x1') f5_x2 = Fun(x2 * 0.5, [x0, x1, x2], 'f5_x2') z0 = Point({ 'coordarray': [3., 2., 1.], 'coordnames': ['x0', 'x1', 'x2'] }) # could also have defined F directly from f5_x[i] definitions F1 = Fun( [ f5_x0(x0, x1, x2), f5_x1(x0, x1, x2), f5_x2(x0, x1, x2) ], [x0, x1, x2], 'F' ) F2 = [ f5_x0(x0, x1, x2), f5_x1(x0, x1, x2), f5_x2(x0, x1, x2) ] assert Diff(F1, [x0, x1, x2]) == Diff(F2, [x0, x1, x2]) assert_array_almost_equal( Diff(F1, [x0, x1, x2]).eval(z0).tonumeric(), array([[1.0, 0, 3.0], [5, 0, 0], [0, 0, 0.5]]) ) assert_array_almost_equal( Diff(F2, [x0, x1, x2]).eval(z0).tonumeric(), array([[1.0, 0, 3.0], [5, 0, 0], [0, 0, 0.5]]) ) def F3(z): return Point({ 'coorddict': { 'x0': z('x0') * z('x2'), 'x1': z('x0') * 5.0, 'x2': z('x2') * 0.5 } }) assert_array_almost_equal( simplifyMatrixRepr(diff(F3, z0, axes=['x1', 'x2'])), Diff(F1, [x0, x1, x2]).eval(z0).tonumeric()[1:] ) # Comparing 1st order Taylor series for nearby point to actual value: z1 = Point({ 'coordarray': array([3.1, 2., .94]), 'coordnames': ['x0', 'x1', 'x2'] }) actual = F3(z1) approx = F3(z0) + simplifyMatrixRepr(diff(F3, z0)).dot(z1 - z0) assert all([err < 0.01 for err in abs(approx - actual)])
def test_symbolic_diff(): """Showing the variety of ways that symbolic Diff() can be used.""" x = Var('x') y = Var('y') xx = QuantSpec('dummy', 'x') function_variants = ('[-3*x**2+2*(x+y),-y/2]', ['-3*x**2+2*(x+y)', '-y/2'], [-3 * Pow(x, 2) + 2 * (x + y), -y / 2]) for f in function_variants: for v in ('x', x, xx): assert str(Diff(f, v)) == '[-6*x+2,0]' for f in function_variants: for v in (['x', 'y'], [x, y], [xx, y]): assert str(Diff(f, v)) == '[[-6*x+2,2],[0,-0.5]]'
""" Cross-channel coupling for a biophysical neural network. Example courtesy of Mark Olenik (Bristol University). """ from PyDSTool import Var, Exp, Par, Pow, args from PyDSTool.Toolbox.neuralcomp import voltage, \ ModelConstructor, makeSoma, channel from matplotlib import pyplot as plt v = Var(voltage) # Create placeholder structs to collect together related symbols # (not used internally by PyDSTool) NMDA = args() KCa = args() # Calcium concentration through nmda channels # Ca_nmda won't create a current but will be used for KCa.I Ca_nmda = args() Iapp = args() NMDA.g = Par(0.75, 'g') NMDA.erev = Par(0., 'erev') KCa.g = Par(0.0072, 'g') KCa.erev = Par(-80., 'erev') Ca_nmda.erev = Par(20., 'Ca_erev') Ca_nmda.rho = Par(0.0004, 'rho') Ca_nmda.delta = Par(0.002, 'delta') Iapp.amp = Par(0.0, 'amp') NMDA.p = Var('p') # nmda gating variable Ca_nmda.c = Var('c') # concentration
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)]'
def test_symbolic_vector(): # XXX: doesn't work without global global q0, q1 p0 = Var("p0") q0 = Var(p0 + 3, "q0") q1 = Var(Diff(1 + Sin(Pow(p0, 3) + q0), p0), "q1") qv = Var([q0, q1], "q") assert str(qv()) == "[q0,q1]" assert str(qv.eval()) == "[(p0+3),(3*Pow(p0,2)*Cos(Pow(p0,3)+(p0+3)))]" v = Var("v") w = Var("w") f = Var([-3 * Pow((2 * v + 1), 3) + 2 * (w + v), -w / 2], "f") df = Diff(f, [v, w]) assert str(df) == "[[-3*6*Pow((2*v+1),2)+2,2],[0,-0.5]]" dfe = df.eval(v=3, w=10).tonumeric() assert_allclose(dfe, [[-880.0, 2.0], [0.0, -0.5]]) assert isinstance(dfe, ndarray) assert isinstance(df.fromvector(), list) y0 = Var("y0") y1 = Var("y1") y2 = Var("y2") t = Var("t") ydot0 = Fun(-0.04 * y0 + 1e4 * y1 * y2, [y0, y1, y2], "ydot0") ydot2 = Fun(3e7 * y1 * y1, [y0, y1, y2], "ydot2") ydot1 = Fun(-ydot0(y0, y1, y2) - ydot2(y0, y1, y2), [y0, y1, y2], "ydot1") F = Fun([ydot0(y0, y1, y2), ydot1(y0, y1, y2), ydot2(y0, y1, y2)], [y0, y1, y2], "F") assert F.dim == 3 DF = Diff(F, [y0, y1, y2]) DF0, DF1, DF2 = DF.fromvector() assert_approx_equal(DF0.fromvector()[0].tonumeric(), -0.04) # str(Diff(F,[y0,y1,y2])) should be (to within numerical rounding errors): # '[[-0.04,10000*y2,10000*y1],[0.040000000000000001,(-10000*y2)-30000000*2*y1,-10000*y1],[0,30000000*2*y1,0]]') jac = Fun(Diff(F, [y0, y1, y2]), [t, y0, y1, y2], "Jacobian") assert jac(t, 0.1, y0 + 1, 0.5).eval(y0=0) == jac(t, 0.1, 1 + y0, 0.5).eval(y0=0) assert jac(t, 0.1, y0, 0.5) == jac(t, 0.1, 0 + y0, 0.5) x = Var("x") y = Var("y") f1 = Fun([-3 * x ** 3 + 2 * (x + y), -y / 2], [x, y], "f1") f2 = ["-3*x**3+2*(x+y)", "-y/2"] f3 = [-3 * x ** 3.0 + 2 * (x + y), -y / 2.0] assert str(f1) == "f1" assert str(f2) == "['-3*x**3+2*(x+y)', '-y/2']" assert str(f3) == "[QuantSpec __result__ (ExpFuncSpec), QuantSpec __result__ (ExpFuncSpec)]" f4 = [-3 * Pow((2 * x + 1), 3) + 2 * (x + y), -y / 2] xx = QuantSpec("dummy", "x") f5 = Var([-3 * Pow((2 * x + 1), 3) + 2 * (x + y), -y / 2], "f5") assert Diff(f1, x) == Diff(f1, "x") assert str(Diff(f1, x)) == "[-3*3*Pow(x,2)+2,0]" assert str(Diff(f3, x)) == "[-3*3*Pow(x,2)+2,0]" assert str(Diff(f3, xx)) == "[-3*3*Pow(x,2)+2,0]" assert str(Diff(f4, x)) == "[-3*6*Pow((2*x+1),2)+2,0]" assert str(Diff(f4, xx)) == "[-3*6*Pow((2*x+1),2)+2,0]" # Examples of Jacobian Diff(f, [x,y])... assert Diff(f1, [x, y]) == Diff(f1, ["x", "y"]) == Diff(f1(x, y), [x, y]) assert str(Diff(f2, ["x", "y"])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f3, ["x", "y"])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f1, [xx, y])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f1, [xx, "y"])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f2, [x, y])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f3, [x, y])) == "[[-3*3*Pow(x,2)+2,2],[0,-0.5]]" assert str(Diff(f4, [x, y])) == "[[-3*6*Pow((2*x+1),2)+2,2],[0,-0.5]]" df5 = Diff(f5, [x, y]) assert str(df5) == "[[-3*6*Pow((2*x+1),2)+2,2],[0,-0.5]]" assert_allclose(df5.eval(x=3, y=10).tonumeric(), [[-880.0, 2.0], [0.0, -0.5]]) # FIXME: segmentation fault! # assert_allclose(df5.eval(x=3,y=10).fromvector(0), [-880.0,2.0]) assert str(df5.eval(x=3, y=10).fromvector(0)) == "[-880.0,2]" assert str(df5.fromvector(0)) == "[-3*6*Pow((2*x+1),2)+2,2]" assert isinstance(df5.fromvector(), list) a = df5.fromvector(0).eval(x=3, y=10).tonumeric() b = df5.eval(x=3, y=10).tonumeric()[0] assert a[0] == b[0] and a[1] == b[1]
def test_symbolic_vector(): # XXX: doesn't work without global global q0, q1 p0 = Var('p0') q0 = Var(p0 + 3, 'q0') q1 = Var(Diff(1 + Sin(Pow(p0, 3) + q0), p0), 'q1') qv = Var([q0, q1], 'q') assert str(qv()) == '[q0,q1]' assert str(qv.eval()) == '[(p0+3),(3*Pow(p0,2)*Cos(Pow(p0,3)+(p0+3)))]' v = Var('v') w = Var('w') f = Var([-3 * Pow((2 * v + 1), 3) + 2 * (w + v), -w / 2], 'f') df = Diff(f, [v, w]) assert str(df) == '[[-3*6*Pow((2*v+1),2)+2,2],[0,-0.5]]' dfe = df.eval(v=3, w=10).tonumeric() assert_allclose(dfe, [[-880.0, 2.0], [0.0, -0.5]]) assert isinstance(dfe, ndarray) assert isinstance(df.fromvector(), list) y0 = Var('y0') y1 = Var('y1') y2 = Var('y2') t = Var('t') ydot0 = Fun(-0.04 * y0 + 1e4 * y1 * y2, [y0, y1, y2], 'ydot0') ydot2 = Fun(3e7 * y1 * y1, [y0, y1, y2], 'ydot2') ydot1 = Fun(-ydot0(y0, y1, y2) - ydot2(y0, y1, y2), [y0, y1, y2], 'ydot1') F = Fun([ydot0(y0, y1, y2), ydot1(y0, y1, y2), ydot2(y0, y1, y2)], [y0, y1, y2], 'F') assert F.dim == 3 DF = Diff(F, [y0, y1, y2]) DF0, DF1, DF2 = DF.fromvector() assert_approx_equal(DF0.fromvector()[0].tonumeric(), -0.04) # str(Diff(F,[y0,y1,y2])) should be (to within numerical rounding errors): # '[[-0.04,10000*y2,10000*y1],[0.040000000000000001,(-10000*y2)-30000000*2*y1,-10000*y1],[0,30000000*2*y1,0]]') jac = Fun(Diff(F, [y0, y1, y2]), [t, y0, y1, y2], 'Jacobian') assert jac(t, 0.1, y0 + 1, 0.5).eval(y0=0) == jac(t, 0.1, 1 + y0, 0.5).eval(y0=0) assert jac(t, 0.1, y0, 0.5) == jac(t, 0.1, 0 + y0, 0.5) x = Var('x') y = Var('y') f1 = Fun([-3 * x**3 + 2 * (x + y), -y / 2], [x, y], 'f1') f2 = ['-3*x**3+2*(x+y)', '-y/2'] f3 = [-3 * x**3. + 2 * (x + y), -y / 2.] assert str(f1) == 'f1' assert str(f2) == '[\'-3*x**3+2*(x+y)\', \'-y/2\']' assert str( f3 ) == '[QuantSpec __result__ (ExpFuncSpec), QuantSpec __result__ (ExpFuncSpec)]' f4 = [-3 * Pow((2 * x + 1), 3) + 2 * (x + y), -y / 2] xx = QuantSpec('dummy', 'x') f5 = Var([-3 * Pow((2 * x + 1), 3) + 2 * (x + y), -y / 2], 'f5') assert Diff(f1, x) == Diff(f1, 'x') assert str(Diff(f1, x)) == '[-3*3*Pow(x,2)+2,0]' assert str(Diff(f3, x)) == '[-3*3*Pow(x,2)+2,0]' assert str(Diff(f3, xx)) == '[-3*3*Pow(x,2)+2,0]' assert str(Diff(f4, x)) == '[-3*6*Pow((2*x+1),2)+2,0]' assert str(Diff(f4, xx)) == '[-3*6*Pow((2*x+1),2)+2,0]' # Examples of Jacobian Diff(f, [x,y])... assert Diff(f1, [x, y]) == Diff(f1, ['x', 'y']) == Diff(f1(x, y), [x, y]) assert str(Diff(f2, ['x', 'y'])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f3, ['x', 'y'])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f1, [xx, y])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f1, [xx, 'y'])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f2, [x, y])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f3, [x, y])) == '[[-3*3*Pow(x,2)+2,2],[0,-0.5]]' assert str(Diff(f4, [x, y])) == '[[-3*6*Pow((2*x+1),2)+2,2],[0,-0.5]]' df5 = Diff(f5, [x, y]) assert str(df5) == '[[-3*6*Pow((2*x+1),2)+2,2],[0,-0.5]]' assert_allclose( df5.eval(x=3, y=10).tonumeric(), [[-880.0, 2.0], [0.0, -0.5]]) # FIXME: segmentation fault! # assert_allclose(df5.eval(x=3,y=10).fromvector(0), [-880.0,2.0]) assert str(df5.eval(x=3, y=10).fromvector(0)) == '[-880.0,2]' assert str(df5.fromvector(0)) == '[-3*6*Pow((2*x+1),2)+2,2]' assert isinstance(df5.fromvector(), list) a = df5.fromvector(0).eval(x=3, y=10).tonumeric() b = df5.eval(x=3, y=10).tonumeric()[0] assert a[0] == b[0] and a[1] == b[1]