Skip to content
This repository


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

A Perlish Interface to Solving ODEs using GSL v1.15+

branch: master

Fetching latest commit…


Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 src
Octocat-spinner-32 t
Octocat-spinner-32 Build.PL
Octocat-spinner-32 Changes
Octocat-spinner-32 MANIFEST
Octocat-spinner-32 META.json
Octocat-spinner-32 META.yml
Octocat-spinner-32 README.pod


 use PerlGSL::DiffEq;
 #Differential Equation(s)
 sub eqn {
   #initial conditions returned if called without parameters
   unless (@_) {
     return (0,1);
   my ($t, @y) = @_;
   #example:   y''(t)==-y(t)
   my @derivs = (
     $y[1],     # y'[0] = y[1]
     -$y[0],    # y'[1] = - y[0]
   return @derivs;
 $sine = ode_solver(\&eqn, [0, 2*3.14, 100]);


This module provides a Perl-ish interface to the Gnu Scientific Library's (GSL) ODEIV2 library, (documentation). This library is the new ordinary differential equation solver as of GSL version 1.15.


This module used to be named Math::GSLx::ODEIV2, a name I never liked. After writing interfaces to GSL's integration libraries I decided to unite the modules under a common namespace PerlGSL. This namespace/distribution contains modular interfaces to the GSL. Read more in the documentation for PerlGSL.


This module is in an beta state. It needs more tests and the ability to configure more of the options that the GSL library allows. Currently this module leans on the fact that GSL has an extensive test suite. While the author has put some thought into the interface it may change in the future as the above mentioned functionality is added or as bugs appear. Bug reports are encouraged!

Also, as of version 0.06, support for including a Jacobian of the system has been added, including the step types that this allows, however this functionality is almost totally untested. Until some of the stiff/extreme test cases can be ported from GSL the author is not certain the the functionality has been properly implemented. Sadly t/sine.* pass even when not properly implemented, which is unnerving. Caveat emptor.



This is the main function of the module.

 $solution = ode_solver( $diffeq_code_ref, $t_range)


 $solution = ode_solver( $diffeq_code_ref, $t_range, $opts_hashref)


 $solution = ode_solver( [$diffeq_code_ref, $jacobian_code_ref], $t_range, $opts_hashref)

Before detailing how to call ode_solver, lets see how to construct the differential equation system.

the differential equation system

The differential equation system is defined in a code reference (in the example $diffeq_code_ref). This code reference (or anonymous subroutine) must have a specific construction:

  • If called without arguments (i.e. $diffeq_code_ref->()) it should return the initial conditions for the system, the number of initial values returned will set the number of differential equations.
  • When called with arguments, the first argument will be time (or the independent parameter) and the rest will be the function values in the same order as the initial conditions. The returns in this case should be the values of the derivatives of the function values.

    If one or more of the returned values are not numbers (as determined by Scalar::Util looks_like_number), the solver will immediately return all calculations up until (and not including) this step, accompanied by a warning. This may be done intentionally to exit the solve routine earlier than the end time specified in the second argument.

  • Please note that as with other differential equation solvers, any higher order differential equations must be converted into systems of first order differential equations.

Optionally the system may be further described with a code reference which defines the Jacobian of the system (in the example $jacobian_code_ref). Again, this code reference has a specific construction. The arguments will be passed in exactly the same way as for the equations code reference (though it will not be called without arguments). The returns should be two array references.

  • The first is the Jacobian matrix formed as an array reference containing array references. It should be square where each dimension is equal to the number of differential equations. Each "row" contains the derivatives of the related differential equations with respect to each dependant parameter, respectively.
      [ d(dy[0]/dt)/d(y[0]), d(dy[0]/dt)/d(y[1]), ... ],
      [ d(dy[1]/dt)/d(y[0]), d(dy[1]/dt)/d(y[1]), ... ],
      [ ..., d(dy[n]/dt)/d(y[n])],
  • The second returned array reference contains the derivatives of the differential equations with respect to the independant parameter.
     [ d(dy[0]/dt)/dt, ..., d(dy[n]/dt)/dt ]

The Jacobian code reference is only needed for certain step types, those step types whose names end in _j.

required arguments

ode_solver requires two arguments, they are as follows:

first argument

The first argument may be either a code reference or an array reference containing one or two code references. In the single code reference form this represents the differential equation system, constructed as described above. In the array reference form, the first argument must be the differential equation system code reference, but now optionally a code reference for the Jacobian of the system may be supplied as the second item.

second argument

The second argument, $t_range, specifies the time values that are used for the calculation. This may be used one of two ways:

  • An array reference containing numbers specifying start time, finish time, and number of steps.
  • A scalar number specifying finish time. In this case the start time will be zero and 100 steps will be used.

optional argument (the options hash reference)

The third argument, $opts_hashref, is a hash reference containing other options. They are as follows:

  • type specifies the step type to be used. The default is rk8pd. The available step types can be found using the exportable function "get_step_types". Those step types whose name ends in _j require the Jacobian.
  • h_init the initial "h" step used by the solver. Defaults to 1e-6.
  • h_max the maximum "h" step allowed to the adaptive step size solver. Set to zero to use the default value specified the GSL, this is the default behavior if unspecified. Note: the module will croak if h_init is set greater than h_max, however if h_init is not specified and the default would violate this relation, h_init will be set to h_max implicitly.
  • Error scaling options. These all refer to the adaptive step size contoller which is well documented in the GSL manual.
    • epsabs and epsrel the allowable error levels (absolute and relative respectively) used in the system. Defaults are 1e-6 and 0.0 respectively.
    • a_y and a_dydt set the scaling factors for the function value and the function derivative respectively. While these may be used directly, these can be set using the shorthand ...
    • scaling, a shorthand for setting the above option. The available values may be y meaning {a_y = 1, a_dydt = 0} (which is the default), or yp meaning {a_y = 0, a_dydt = 1}. Note that setting the above scaling factors will override the corresponding field in this shorthand.


The return is an array reference of array references. Each inner array reference will contain the time and function value of each function in order as above. This format allows easy loading into PDL if so desired:

 $pdl = pdl($solution);

of course one may recover one column by simple use of a map:

 @solution_t_vals  = map { $_->[0] } @$solution;
 @solution_y1_vals = map { $_->[1] } @$solution;

For a usage example see the "SYNOPSIS" for a sine function given by y''(t)=-y(t).



Returns the available step types which may be specified in the "ode_solver" function's options hashref. Note that those step types whose name end in _j require the Jacobian.


A simple function taking no arguments and returning the version number of the GSL library as specified in gsl/gsl_version.h. This was originally used for dependency checking but now remains simply for the interested user.


On systems with PDL installed, I would like to include some mechanism which will store the numerical data in a piddle directly, saving the overhead of creating an SV for each of the pieces of data generated. I envision this happening as transparently as possible when PDL is available. This will probably take some experimentation to get it right.


PDL, website



Joel Berger, <>


Copyright (C) 2012 by Joel Berger

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The GSL is licensed under the terms of the GNU General Public License (GPL)

Something went wrong with that request. Please try again.