Thanks for your email and patch. I had noticed that integration-qag appeared to be non-reentrant a couple years ago, and made a little progress into diagnosing the problem, but didn't get as far as you have. I think your solution is a good start. As far as callbacks defined through defmobject, it seems like this could be handled by let binding in the defmcallback expansion, since they are only ever called in the CBFN functions. What do you think?
As a side point, it looks like you're trying to do a multivariate integral. I think you will find the Monte Carlo integration better than nested calling of univariate integrations for this purpose.
Liam
On Fri, Jan 9, 2015 at 1:37 PM, Eugene Zhemchugov jini.zh@gmail.com wrote:
I was trying to evaluate a recurring integral when I ran into what I think a design flaw in the callbacks implementation. Consider the following code:
(integration-qag (lambda (x) (integration-qag (lambda(y) (* (sin x) y)) 0d0 1d0 :gauss41)) 0d0 pi :gauss41)
The result of the integration should be 1, but I get 4.93. Digging through the code, I figured out that callbacks are implemented in the following way:
- During the GSLL compilation, a callback is defined via the
CFFI:DEFCALLBACK macro. 2. The GSLL wrapper function assigns the function to be called to a dynamic variable and calls the underlying GSL function. 3. The GSL function calls the CFFI callback. 4. The CFFI callback calls the value stored in the dynamic variable.
The relevant part of the GSLL wrapper function is generated by BODY-EXPAND. Here is a simplified version of the code generated for INTEGRATION-QAG:
(defun integration-qag (function ...) (declare (special integration-qag-dynfn0)) (setf integration-qag-dynfn0 function) (foreign-funcall "gsl_integration_qag" ...))
The problem here is that if the function passed as a parameter to the GSLL function calls the same GSLL function again, as in the example above, the dynamic variable value is overwritten during the second call, and then the first GSL function ends up calling the second callback all the time. Seemingly, this can be fixed by binding instead of assigning the dynamic variable, i.e., by making BODY-EXPAND to generate code like this:
(defun integration-qag (function ...) (let ((integration-qag-dynfn0 function)) (declare (special integration-qag-dynfn0)) (foreign-funcall "gsl_integration_qag" ...)))
In this case the value of INTEGRATION-QAG-DYNFN0 is restored upon leaving the LET form. However, having patched the code this way, I broke callbacks introduced via the DEFMOBJECT macro. In this case the assignment happens in the REINITIALIZE-INSTANCE method specialized on this object, which is usually called in the construction phase. As an example, consider NONLINEAR-LEAST-SQUARES-EXAMPLE. The assignment is made during the call to MAKE-NONLINEAR-FDFFIT, however the callback is executed during the call to ITERATE. I think that the binding should be performed in ITERATE, as soon as it is needed. ITERATE receives an instance of an object subclassed from CALLBACK-INCLUDED, hence it has access both to the functions to be called (the FUNCALLABLES slot of CALLBACK-INCLUDED) and the callback specification (the CBINFO slot). But I don't know what would be the best way to implement it. One possibility is to loop through function parameters in BODY-EXPAND and figure out which are instances of CALLBACK-INCLUDED. That will work only for methods, and only for the specialized parameters. Is it sufficient? Other approaches I can think of would require changing the DEFMFUN interface to specify which parameters should be used to construct the bindings. What solution would you propose? I can make a patch for it if you don't think that the changes are too drastic to trust not an upstream developer.
You may find my partial patch in the attachement.
Gsll-devel mailing list Gsll-devel@common-lisp.net http://mailman.common-lisp.net/cgi-bin/mailman/listinfo/gsll-devel