This is a call for people willing to relieve me in the task of maintaining a library for parsing, evaluating and differentiating real functions with almost optimal speed and precision without recourse to using multiprecision real types. I have it working for years in Windows 32 bits, and I think that it could be a nice thing to extend it in fpc-Lazarus to other CPU and FPU architectures.
The hardest thing has been already done and tested: to conceive it and to build a working model.
1. SOME HISTORY
For almost thirty years I have been a teacher of differential geometry in Valencia, Spain. I retired two years ago. Along these years I have written several programs oriented to teaching and research, all for Windows 32 bits, and all free. Some of them may be retrieved freely and with source code in
Perhaps the prettiest of them is Superficies_En, wich is an English version. Dont't be afraid by the language barrier for the others: almost all sources are written in English.
After studying the code of a library built years ago by Dmitry Kaschenko and Vladimir Safin, I wrote first another one with a different parsing mechanism and with some safety measures. Then, I added the possibility of parsing functions defined with integrals. Finally, I added differentiation.
All this done in Delphi with some trials in Kylix and Lazarus.
Now, I feel that I lack the energy and memory to learning the 64 bits amd-intel x67 architecture, and the more so for other ones. Thus, I may opt by wainting to Delphi 64 bits and then hope for the best, that is that by examining the debugging CPU window I become able to translate the library to 64 bits. Or else, to provide others with the present code (by the way, it has been open in my web page for years) and with advice about the underlying theory and tricks. If I find interested people, my first task would be to write with more detail my notes about the theory and to document better the present code.
2. OVERVIEW
This is how it works from the viewpoint of the programmer. Integrals are not included here for brevity:
Supppose the programmer needs, for example, to treat a mathematical problem in which some real (that is, with result Double or Extended) function in three independent (resp. Double or Extended) variables denoted x, y, z is to be used. Suppose that the user has input that function as the string
fstr:= 'cos(py + sin(3.22x+ qz^3)) - 1/2',where p and q are considered as parameters.
For example, the user wants the program to draw the surface defined implicitly by the equation
cos(py + sin(3.22x+ qz^3)) - 1/2 = 0
The programmer should create an instance of TOCFunctDDDoubleSafe by a call as
theF:= TOCFunctDDDoubleSafe.Create;Then, the programmer parses fstr by a call to
procedure TOCFunctDDDoubleSafe.ParseNewText(t, vars, pars:
AnsiString);Here, t is the string defining the function, vars is the string containing the allowed independent variables, and pars is the string containing the allowed parameters. In our case, we could call
theF.ParseNewText(fstr, 'xyz', 'pq');If pars '', the programmer must call at least one time the updater of parameter values. That is for instance
theF.UpdateParameters([3.42, -2.2]);This means that until another call to UpdateParameters, the parameters p and q will have the values p = 3.42 and q = -2.2.
Now the programmer may obtain the value of the function by a call as
a:= theF.F([1.1, 0, sqrt(5)]),where a will be the value of the function when x = 1.1, y = 0 and z = sqrt(5).
For computing the first derivatives of the function, the programmer must call
theF.BuildFirstDerivative;Then, the following function is available
TOCFunctDDDoubleSafe.FD(XV: array of Double): Fd;where
Fd= record
f, v: Double;
end;And for computing the second derivatives, the programmer must call
theF.BuildSecondDerivative;and then the following function is available
TOCFunctDDDoubleSafe.FDD(XVA: array of Double): Fdd;where
Fdd= record
f, v, a: Double;
end;An example: the value of the function and its first partial derivative with respect to 'y' at the point (a,b,c) is obtained by calling:
anFD:= theF.FD([a, b, c, 0, 1, 0]);So, anFD.f shall be the value of the function at (a,b,c), and anFD.v shall be the value of that partial derivative at (a,b,c).
In the same manner, the value of the function and its first and second partial derivatives with respect to 'y' at the point (a,b,c) are obtained by calling:
anFDD:= theF.FDD([a, b, c, 0, 1, 0, 0, 0, 0]);So, anFDD.f shall be the value of the function at (a,b,c), anFDD.v shall be the value of the partial derivative with respect to 'y' at (a,b,c), and anFDD.a the value of the second partial derivative with respect to 'y' at (a,b,c).
The meaning of the three last slots that seem to be useless, and the manner for computing crossed partial derivatives requires some elaboration that I can provide to the interested persons.
The important thing is that the computation of the function and its derivatives is hard-coded in object code without the use of finite differences. Thus, one may expect for theF.FD a precision similar to that one could obtaine by having precompiled with Delphi (or fpc) the function
function afunction(a, b, c: Double): Fd;
begin
fd.x:= cos(p*y + sin(3.22*x+ q*z*sqr(z))) - 1/2
fd.v:= -p*sin(p*y + sin(3.22*x+ q*z*sqr(z)));
end;and the same for theF.DD. In general, my library shall be faster than the precompiled function.
3. MATHEMATICAL BASIS OF DIFFERENTIATION CODE
Essentially, it is the application of the chain rule to the object code. That is, to extend the technique known as "automatic differentiation" at the object level of code (instead to the high level of code). I do not know whether this is new: I haven't found it the computing literature: at least when I began to write it. After I wrote it, I haven't had the need to search for it. If you know of something similar, tell me please.
Googling for "automatic differentiation" could give an initial idea of the underlying mechanism.
If you download the full distro of Superficies_En, you will see in the source folder a file with title:
"Object code for the first and second differential of a function with the instruction set x86.rtf"
It is a roughly written report about the thing, excluding integration. About integration, I use splines for interpolation: see in that folder the file "AproxFuncBSplinesEnglish.pdf". I think that my technique for B-spline interpolation is also new, but I am not sure of it.
The relevant pascal unit in the source folder is
OCFunctDDDoubleSafeIntegrals.pas
Best regards
