ccgsl: a C++ interface for the gnu Scientific Library
To make it easier to avoid bugs
One of the main reasons for using C++ instead of C for scientific computing is that C++ code can give the compiler much more opportunity to detect problems at compile time rather than let them show up at run time. In, particular, C++ makes it much easier to avoid memory leaks from forgetting to delete or free a pointer or from reading beyond the end of a range. So ccgsl discourages the use of gsl pointers in favour of its own shared pointers, which, like std::shared_ptr delete the object pointed to when and only when there is no shared pointer pointing to it. In addition, ccgsl allows you to use objects like gsl::vector or std::vector that contain a size() function where gsl would require a C-style array and its length as arguments.
To provide an lightweight interface using only header filesA heavyweight interface or one that requires a new library be installed does not give the compiler the opportunity to optimise away the interface code as much as possible. So ccgsl maintains its interface as classes and namespaces containing inline functions that often do no more than extract pointers to a gsl structs and pass them to gsl functions.
To resemble gsl
It should be possible to guess from the gsl documentation what ccgsl header is required and what functions arguments are likely needed. The standard way ccgsl achieves this are as follows.
To work with existing C++ code
It is not reasonable to assume that everyone will start from ccgsl-compliant code. So ccgsl needs to be adaptable. A common area of incompatibility is that in C++ it is natural to create function objects to represent parametrised functions. That is, where a function has both fixed parameters and variable arguments, in C++ we can define the class F and pass the parameters to its constructor. Then an object f of class F can be regarded as a function that is called using a method of F. For example, F may contain a function double F::function( double x ) or even double F::operator()( double x ) that we can call using f.function( x ) or f( x ). However, we cannot construct any of the gsl function structs directly from F::function because they require a pointer to a function as an argument and do not permit a pointer to a member function. So ccgsl contains classes such as gsl::function_scl that can be constructed from a function or member function and that gsl can use exactly as if they were its own structs.
Ccgsl is also designed to allow std::vector<T> or similar arguments to be supplied instead of double ones wherever possible. This should allow it to work reasonably with existing code. So, for example, gsl::mean( array ) correctly returns the mean of a std::vector<double> array.
To be freely mixable with gsl
Although ccgsl is designed so you should not need to use gsl directly, you may already have code using gsl. So ccgsl is designed to allow you to use existing code reasonably easily. For example, suppose you have a function that requires a pointer to a gsl_vector struct and wish to pass a ccgsl::vector v. Then you would pass v.get() instead.
You can also construct gsl::vector and gsl::matrix objects from gsl_vector and gsl_matrix pointers, though some care is needed. The default behaviour is for the ccgsl object to delete the pointer when the ccgsl object goes out of scope. So the default behaviour should be used if existing code does not free the gsl pointer (or can be suitably adapted). There are non-default alternatives that wrap gsl_vector and gsl_matrix pointers without ownership.
To be compatible with the standard template library where appropriate
The block and vector classes in ccgsl implement the container concept. This means that you can write code like the following and expect it to work.
To allow you to drop function arguments with obvious default values.
C++ allows function overloading, often through default argument values. So ccgsl exploits this to let you drop arguments that you normally would not wish to specify explicitly. One obvious example is the stride of an array, which is most usually 1.
To include documentation
To be object oriented
Object-orientation has many benefits. But it is not a magic bullet. An object-oriented interface to gsl would necessarily be heavier than it need be and would likely put restrictions on what sort of C++ code could be used with it. So ccgsl maintains much of the functional programming approach of gsl, but organises it into the nested namepaces and classes suggested by its naming conventions. This approach will not change.
To provide template classes or functions
Since C++ has templates, an attractive idea is to declare template classes like gsl::vector<T> and then define specialisations like gsl::vector<double>, gsl::vector<long double> and gsl::vector<complex>. This doesn’t work so well in practice: gsl only offers a limited range of alternatives to double and these include its own complex class, which is a little idiosyncratic. So template specialisations would require rewriting gsl except in special cases.
Internally, ccgsl uses template classes extensively. But these are mainly designed to be called with the template argument deduced using argument-dependent lookup so that the argument may be assumed to be of an unspecified class that implements a concept. For example, gsl::poly::eval( coefficients, x ) evaluates a polynomial at a value x with coefficients given by a template class that must contain double* data() and size_t size() const member functions. This includes std::vector and gsl::vector.
Last modified: Sun 03 Mar 2013 09:17 am