In response to Williams sage-2.0 plan I wanted to describe what I had done with using gsl to implement a numerical ode solver. I believe that the patch containing this will be applied after doing a recent pull or upgrade but I'm not sure(is this true?). If not I can send patches for people to play with. I have included the documentation at the end so people can look at the syntax.
To see the documentation and examples sage: ode_solver? To be done 1. Testing/feedback: Is it easy to use compared to matlab,mathematica. Any bugs or ways to crash it (unexpected input or user specified functions that do weird things)? 2. More examples, doctests, improved documentation (I noticed a bunch of typos just copying the documentation below) 3. Obvious additions people think would be useful. Currently it has a plotting routine and a routine to produce an interpolated function from the data points. Ideas for extension: 1. It would be nice if there was some facility for automatically converting a nth order ODE to a system of first order ones. 2. It would be nice if there was some facility for automatically computing the jacobian when the functions involved are rational functions and elementary functions. 3. Numerically computing the jacobian: For the algorithms that require the jacobian It would be possible to numerically compute the jacobian, however I was wary of doing this by default. Does anyone have any knowledge about the benefits of this, can it cause instability (using the numerical jacobian instead of the exact one). Accuracy testing: 1. I believe there are standard batches of tests for ode solvers. it would be interesting if some of these could be applied to compare the accuracy with matlab for example. This ode solver will be slower than matlab's on systems that require many function evaluations because we are forced to use python functions and there is significant overhead in calling these. Still comparisons would be interesting. There is a way to use compiled functions describe in the documentation but requires writing the functions in C and so isn't really suitable for general users. ____________________________________________________________________ ode_solver is a class that wraps the GSL libraries ode solver routines To use it instantiate a class, sage: T=ode_solver() To solve a system of the form dy_i/dt=f_i(t,y), you must supply a vector or tuple/list valued function f representing f_i. The functions f and the jacobian should have the form foo(t,y) or foo(t,y,params). params which is optional allows for your function to depend on one or a tuple of parameters. Note if you use it, params must be a tuple even if it only has one component. For example if you wanted to solve y''+y=0. You need to write it as a first order system y_0' = y_1 y1_1 = -y_0 In code, sage: f = lambda t,y:[y[1],-y[0]] sage: T.function=f For some algorithms the jacobian must be supplied as well, the form of this should be a function return a list of lists of the form [ [df_1/dy_1,...,df_1/dy_n], ..., [df_n/dy_1,...,df_n,dy_n], [df_1/dt,...,df_n/dt] ]. There are examples below, if your jacobian was the function my_jacobian you would do. sage: T.jacobian=my_jacobian There are a variety of algorithms available for different types of systems. Possible algorithms are "rkf45" - runga-kutta-felhberg (4,5) "rk2" - embedded runga-kutta (2,3) "rk4" - 4th order classical runga-kutta "rk8pd" - runga-kutta prince-dormand (8,9) "rk2imp" - implicit 2nd order runga-kutta at gaussian points "rk4imp" - implicit 4th order runga-kutta at gaussian points "bsimp" - implicit burlisch-stoer (requires jacobian) "gear1" - M=1 implicit gear "gear2" - M=2 implicit gear The default algorithm if rkf45. If you instead wanted to use bsimp you would do sage: T.algorithm="bsimp" The user should supply initial conditions in y_0. For example if your initial conditions are y_0=1,y_1=1, would do sage: T.y_0=[1,0] The actual solver is invoked by the method ode_solve. It has arguments t_span, y_0,num_points, params. y_0 must be supplied either as an argument or above by assignment. params which is optional and only necessary if your system uses params can be supplied to ode_solve or by assignment. t_span is the time interval on which to solve the ode. If t_span is a tuple with just two time values then the user must specify num_points, and the system will be evaluated at num_points equally spaced points between t_span[0] and t_span[1]. If t_span is a tuple with more than two values than the values of y_i at points in time listed in t_span will be returned. Error is estimated via the expression D_i = error_abs*s_i+error_rel*(a|y_i|+a_dydt*h*|y_i'|) The user can specify error_abs (1e-10 by default), error_rel (1e-10 by default) a (1 by default), a_(dydt) (0 by default) and s_i (as scaling_abs which should be a tuple and is 1 in all components by default). If you specify one of a or a_dydt you must specify the other. You may specify a and a_dydt without scaling_abs (which will be taken =1 be default) h is the initial step size which is (1e-2) by default. ode_solve solves the solution as a list of tuples of the form, [ (t_0,[y_1,...,y_n]),(t_1,[y_1,...,y_n]),...,(t_n,[y_1,...,y_n])]. This data is stored in the variable solutions sage:T.solution Examples: Consider solving the Van der pol oscillator x''(t) + ux'(t)(x(t)^2-1)+x(t)=0 between t=0 and t= 100. As a first order system it is x'=y y'=-x+uy(1-x^2) Let us take u=10 and use initial conditions (x,y)=(1,0) and use the runga-kutta prince-dormand algorithm. sage: def f_1(t,y,params): ... return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1)] sage: def j_1(t,y,params): ... return [ [0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0,0] ] sage: T=ode_solver() sage: T.algorithm="rk8pd" sage: T.function=f_1 sage: T.jacobian=j_1 sage: T.ode_solve(y_0=[1,0],t_span=[0,100],params=[10],num_points=1000) sage: T.plot_solution() The solver line is equivalent to sage: T.ode_solve(y_0=[1,0],t_span=[x/10.0 for x in range(1000)],params = [10]) Lets try a system y_0'=y_2*y_3 y_1'=-y_0*y_2 y_2'=-.51*y_0*y_1 We will not use the jacobian this time and will change the error tolerances. sage: g_1= lambda t,y: [y[1]*y[2],-y[0]*y[2],-0.51*y[0]*y[1]] sage: T.function=g_1 sage: T.y_0=[0,1,1] sage: T.scale_abs=[1e-4,1e-4,1e-5] sage: T.error_rel=1e-4 sage: T.ode_solve(t_span=[0,12],num_points=100) By default T.plot_solution() plots the y_0, to plot general y_i use sage: T.plot_solution(i=0) sage: T.plot_solution(i=1) sage: T.plot_solution(i=2) The method interpolate_solution will return a spline interpolation through the points found by the solver. By default y_0 is interpolated. You can interpolate y_i through the keyword argument i. sage: f = T.interpolate_solution() sage: plot(f,0,12).show() sage: f = T.interpolate_solution(i=1) sage: plot(f,0,12).show() sage: f = T.interpolate_solution(i=2) sage: plot(f,0,12).show() sage: f = T.interpolate_solution() sage: f(pi) Unfortunately because python functions are used, this solver is slow on system that require many function evaluations. It is possible to pass a compiled function by deriving from the class ode_sysem and overloading c_f and c_j with C functions that specify the system. The following will work in notebook %pyrex cimport sage.gsl.ode import sage.gsl.ode include 'gsl.pxi' cdef class van_der_pol(sage.gsl.ode.ode_system): cdef int c_f(self,double t, double *y,double *dydt): dydt[0]=y[1] dydt[1]=-y[0]-1000*y[1]*(y[0]*y[0]-1) return GSL_SUCCESS cdef int c_j(self, double t,double *y,double *dfdy,double *dfdt): dfdy[0]=0 dfdy[1]=1.0 dfdy[2]=-2.0*1000*y[0]*y[1]-1.0 dfdy[3]=-1000*(y[0]*y[0]-1.0) dfdt[0]=0 dfdt[1]=0 return GSL_SUCCESS After executing the above block of code you can do sage: T=ode_solver() sage: T.algorithm="bsimp" sage: vander=van_der_pol() sage: T.function=vander sage: vander=van_der_pol() sage: T.ode_solve(y_0=[1,0],t_span=[0,2000],num_points=1000) sage: T.plot_solution(i=0) --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://sage.scipy.org/sage/ and http://modular.math.washington.edu/sage/ -~----------~----~----~----~------~----~------~--~---