Science makes it known,
Engineering makes it work,
Art makes it beautiful.
|
|
D .dll Calling FORTRAN .dll
Using D procedures to call
Numerical Recipes: The Art of Scientific Computing1
Silverfrost Fortran 95 subroutines (Simulated Annealing2)
(D Numerical Recipes Procedures)
This is the first part of D .dll (dnrprocs.dll) Calling
FORTRAN .dll's (sttstcs.dll and mathproc.dll). This page
focuses on dnrprocs.dll
(or module dnrprocs), which follows the D code calling D code in
DLLs3 model. This tutorial builds on several previous tutorials.
This is a partial FORTRAN to D port of the Simulated
Annealing FORTRAN subroutines published in
Numerical Recipes: The Art of Scientific Computing.
This was accomplished by porting Numerical Recipes' FORTRAN
subroutine METROP to D boolean function
dMETROP4 and FORTRAN
subroutine ANNEAL to D procedure dANNEAL (source
code download links below).
(module dnrprocs contains additional
procedures from Numerical Recipes' and other sources ported to
D; see note 8 below)
Files:
(Notepad++ was used to create/edit the .d and .di files - the tabbing
and spacing may be off in MS Notepad)
-
wmath3.d
Main Program - simple bare-bones Windows program to demonstrate
Simulated Annealing and procedure dANNEAL (...).
Calls ldAnlTestData(...) in module dnrprocs
(see below) to load test data. To invoke dANNEAL (...),
File, Calculate. dANNEAL
can be called by either a D command line program or a D Windows program.
wmath3.d also serves as an example of writing a very simple D program
creating a Windows application calling WinAPI functions.
-
module
hedtio
files
(hedtio.d,
hedtio.di,
chedtio.bat)
- general purpose Windows Edit Controls I/O, Windows error message
procedures (developed in a different directory than dnrprocs,
copied required files - hedtio.di, hedtio.lib, and
hedtio.dll - to
dnrprocs development directory).
-
module
dnrprocs.d
- module dnrprocs - Numerical Recipes procedures (via
calls to mathproc.dll Simulated Annealing and
Polynomial Root Finding subprograms) and plotting support procedures
(see note 8 below);
dnrprocs.di
- dnrprocs.d D interface file - used when compiling wmath3.d.
dnrprocs.dll - dnrprocs.d dynamic link library;
dnrprocs.lib - dnrprocs.dll import library - used when linking wmath3.exe;
cnrprocs.bat- batch file to compile dnrprocs.d.
-
mathproc.for -
Numerical Recipes
FORTRAN simulated annealing
(as well as other numerical/engineering) subprograms RLEN(...),
RAN3(...), IRBIT1(...), TRNCST(...), TRNSPT(...), REVCST(...), and
REVERS(...). Most of the source code unavailable for
download from this site to avoid any possible copyright violations;
Older Numerical Recipes book editions
available from the
publisher, contains original source code; limited source code available at
Additional subprograms in mathproc.dll
and
mathproc.dll FORTRAN Engineering Subprograms;
mathproc.dll - mathproc.for dynamic link library;
mathproc.lib - mathproc.dll import library - created with
implib
and used when linking dnrprocs.lib;
-
sttstcs.for -
Numerical Recipes
FORTRAN statistical analysis
support subroutine
D12R3MINMAX (...)5;
full source code
unavailable for download from this site to avoid any intellectual
property issues;
Older Numerical Recipes book editions
available
from the publisher, contains original source code;
sttstcs.dll - sttstcs.for dynamic link library;
sttstcs.lib - sttstcs.dll import library - created with
implib
and used when linking dnrprocs.lib;
Procedure dANNEAL in dnrprocs.dll
calls FORTRAN functions RLEN, RAN3, IRBIT1,
FORTRAN subroutines TRNCST, TRNSPT,
REVCST, and REVERS in mathproc.dll.
The key for bringing in the sttstcs.lib
(sttstcs.dll's import library) and mathproc.lib
(mathproc.dll's import library) definitions when
compiling and linking dnrprocs.d into dnrprocs.dll
are the statements:
pragma(lib, "sttstcs.lib"); // include in .di file
pragma(lib, "mathproc.lib"); // include in .di file
(Reminder - Silverfrost Plato FTN95 IDE builds mathproc.dll,
DMD
utility
implib
builds mathproc.lib)
Module (*.d) pragma statements should also be included in the
D interface (*.di) file.
Other key statements6:
HINSTANCE g_hInst; // include in .di file
// called by nrDLL_Initialize and nrDLL_Terminate
extern (C)
{
void gc_setProxy(void* p);
void gc_clrProxy();
}
extern(Windows) int DrawTextA(HDC, LPCSTR, int, LPRECT, UINT);
// upper limit number of data points
const int NRI = (1024);
extern (Pascal)
{
// sttstcs.dll subroutine declarations
void D12R3MINMAX (ref short, ref float, ref float, ref float[NRI], ref short) nothrow;
// mathproc.dll subroutine declarations
float RLEN (ref float, ref float, ref float, ref float, ref float, ref float) nothrow;
float RAN3 (ref short) nothrow;
short IRBIT1 (ref int) nothrow;
void* TRNCST (ref float, ref float, ref short[6], ref short[NRI], ref float[NRI], ref float[NRI], ref float[NRI], ref short, ref short) nothrow;
void* REVCST (ref float, ref float, ref short[6], ref short[NRI], ref float[NRI], ref float[NRI], ref float[NRI], ref short, ref short) nothrow;
void* REVERS (ref short, ref short[6], ref short[NRI], ref short) nothrow;
void* TRNSPT (ref short, ref short[6], ref short[NRI], ref short) nothrow;
}
const int IDX_OFFSET = (-1); // Transform FORTRAN index to D index
// if migrate to full D, s/b able to change to 0
// include in .di file
const int PLOT_ALGEBRA_NORMAL = (2);
const int IMGNARY_ROOT = (105);
const int MAX_ANNEAL_PASSES = (249);
const short V_PT_ADJUST = (5); // Vertical PoinT ADJUSTment
// ------------------------------------------------------------------
// G:\Program Files\Microsoft SDKs\Windows\v7.0\Include
const int DT_LEFT = (0x00000000);
const int DT_TOP = (0x00000000);
const int DT_RIGHT = (0x00000002);
const int DT_BOTTOM = (0x00000008);
const int DT_SINGLELINE = (0x00000020);
const int DC_PEN = (19);
An
extern (...) {...}
declaration with a linkage attribute is needed for
procedures/subprograms [gc_setProxy(...), gc_clrProxy(),
DrawTextA(...)7, D12R3MINMAX(...), RLEN(...), RAN3(...),
IRBIT1(...), TRNCST(...), TRNSPT(...), REVCST(...), and REVERS(...)]
defined in other object files. extern (Pascal) {...}
causes the passed arguments to be Pushed/Popped to/from the stack in a
different order, requiring the parameters passed to the external
subroutines be listed in reverse order. By default, FORTRAN
requires its parameters to be passed by reference (can be overridden in the
FORTRAN subroutine in an all FORTRAN solution).
module level data declarations (g_hInst, IDX_OFFSET,
DT_LEFT, etc.) should be included in the D interface (*.di) file; externs
(with the exception of DllMain) should not be included in the D
interface file.
IDX_OFFSET is used to provide a
FORTRAN to D array index adjustment.
module dnrprocs exported procedures8:
Exported procedure declarations need to be included in the D interface
(*.di) file.
export void ldAnlTestData(ref short nCity,
ref float x[NRI], ref float y[NRI], ref float mu[NRI], ref short iOrder[NRI]) nothrow
export float nScale (HWND hGraph, ref short nPts,
ref short g1, ref short nMin, ref short dz, ref short nMax, ref short g2,
ref short n[NRI], ref float z[NRI], ref short iErr) nothrow
export int plotAxis(HWND hGraph, HDC hdc, LPPOINT lpPoint, float xScale, float yScale,
short gx1, short zx, short gx2,
short gy1, short zy, short gy2, ref int grX, ref int grY) nothrow
export void PathLenCost (ref short nCity,
ref float x[NRI], ref float y[NRI], ref float mu[NRI], ref short iOrder[NRI],
ref float path, ref float eCost, ref short iErr) nothrow
export bool dMETROP (ref float DP, ref float DE, ref float T) nothrow
export void dANNEAL (ref short nCity,
ref float x[NRI], ref float y[NRI], ref float mu[NRI], ref short iOrder[NRI],
ref float path, ref float eCost, ref short iErr, int IOflag, HWND hWnd) nothrow
export void nrDLL_Initialize(void* gc)
export void nrDLL_Terminate()
extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
ldAnlTestData loads simulated annealing test data.
nScale (which calls D12R3MINMAX in sttstcs.dll)
is used in other applications, not called in the wmath3.d
demonstration program.
nScale scales an input float array for graphing, output is a scaled
integer points array. If the output points array does not extend to
the axis (0 value), the float return value is adjusted.
plotAxis
is also used in other applications, not called in the wmath3.d
demonstration program. plotAxis plots an X-Y axis for
graphing applications.
PathLenCost, dMETROP, and dANNEAL are the
Numerical Recipes D procedures.
PathLenCost, extracted from the original FORTRAN ANNEAL
subroutine, initializes and computes the path length and cost of the initial
configuration.
dMETROP, an implementation of the
Metropolis Algorithm, always takes a
downhill step when possible, but will sometimes take an uphill
step (if a downhill step is unavailable) to break out of a local minima
(small scale minmum value) in search of a more optimal global
minima (large scale minmum value) solution. Uphill/downhill here can
refer to cost, energy level, path length, etc.
dANNEAL is the main procedure, calling the external
mathproc.dll subroutines.
Through these calls,
dANNEAL modifies the path (or configuration) of
the X Y coordinates. The arrays x[NRI] and y[NRI] are the
coordinate arrays. Array iOrder[NRI] is an
index array (or configuration table) into x[NRI], y[NRI],
and mu[NRI]. Arrays x[NRI],
y[NRI], and mu[NRI] are not modified, only array iOrder[NRI].
nrDLL_Initialize, nrDLL_Terminate, and DllMain
are dnrprocs.dll housekeeping procedures.
Compiling/Linking:
-
Create, compile, and link the FORTRAN mathproc.for
(it will also be necessary to do the same with the
FORTRAN sttstcs.for,
since it is also used by module dnrprocs in other applications)
-
Prepare the
mathproc.lib import library
using implib (if you have not already done so); the Silverfrost
generated mathproc.lib is not
compatible
with the Digital Mars D compiler/linker. (again, it will also
be necessary to do the same with the
sttstcs.lib import library)
-
Prepare hedtio dll.def; Compile/Link module hedtio
-
Need a dnrprocs
dll.def
file (accessed during compilation)
LIBRARY dnrprocs
DESCRIPTION 'My DLL written in D'
EXETYPE NT
SUBSYSTEM WINDOWS
CODE PRELOAD DISCARDABLE
DATA PRELOAD MULTIPLE
-
Compile and link dnrprocs.d into dnrprocs.dll:
open a D2 32-bit Command Prompt
dmd -c dnrprocs.d -g
dmd dnrprocs.obj dll.def -g
implib /noi /system dnrprocs.lib dnrprocs.dll
(The above three lines comprise cnrprocs.bat; simply copy and
paste using a text editor.)
-
Prepare dnrprocs.di (can be downloaded above) either by adding
-H switch to first dmd command in step 5 and stripping down,
or build from scratch with a text editor using guidelines given on
this page.
If using DMD generated dnrprocs.di, it must be stripped down or
the main program will not compile/link in step 8.
(This is true for the DMD32 v2.066.0 compiler; it may not be true for
other versions)
-
Need a simple
win.def
file
EXETYPE NT
SUBSYSTEM WINDOWS
(For WinXP, may want to use SUBSYSTEM WINDOWS, 4
for additional usability with wndclass.hbrBackground and
"STATIC" HWND
child windows - can very easily make "STATIC" HWND controls
background color the same as the main window. Have found
wndclass.hbrBackground = cast(HBRUSH)COLOR_BTNSHADOW;
in the D program combined with
SUBSYSTEM WINDOWS, 4
in the module definition file produces acceptable results on
WinXP SP3, though it may seem somewhat amateurish at first glance)
-
Compile and link the Windows executable in a D2 32-bit Command Prompt:
dmd wmath3.d hedtio.lib dnrprocs.lib win.def
(Since the pragma statements links in sttstcs.lib and mathproc.lib
in step 5, and wmath3.d does not refer to any subroutines in
either sttstcs.dll or mathproc.dll,
do not need to include sttstcs.lib and mathproc.lib in this step.)
1. Press, William H., Brian P. Flannery, Saul A Teukolsky,
and William T. Vetterling (1986). Numerical Recipes: The Art of Scientific
Computing. New York :
Press Syndicate of the University of Cambridge.
2. Simulated Annealing, also known as the travelling salesman problem,
is used
for combinatorial minimization. The travelling salesman
problem involves a salesman who must travel to a large number of cities
(or nodes, represented by X Y coordinates). What is the shortest
path the salesman
can traverse visiting these cities? In a very large 'solution space',
there are some solutions that are 'low cost'
(global minima as opposed to local minima) relative to
other solutions. Simulated
annealing searches for these 'low cost' solutions.
Simulated annealing has also been applied to designing integrated
circuits. The travelling salesman problem is a NP-Complete
problem,
where N equals the number of nodes (or cities),
and the computation time is proportional to eN.
3. Additional information on writing D DLLs can be found at
Win32 DLLs in D
4. A contributing factor to this hybrid solution was one of
known problems D calling FORTRAN.
5. D12R3MINMAX (...) is used in other applications which is called by
nScale (...), not called in the wmath3.d demonstration program.
There are several procedures/subprograms in the various
.dll's not called (directly or indirectly) by the wmath3.d demonstration program.
See note 8 below.
6. Since the travelling salesman problem is a NP-Complete problem, it
can require over 20,000 passes through the data. Steps must be
taken to delay an Access Violation. I found that by making the
FORTRAN calls nothrow delayed the Access Violation by
about 1000
passes. To prevent an Access Violation, dANNEAL exits graciously
after 20000 passes. The calling program can then optionally call
dANNEAL again with the partially annealed data for further annealing.
Code excerpts are from dnrprocs.d, not dnrprocs.di. D Interface files
have a slightly different format. Download and compare dnrprocs.d
and dnrprocs.di.
7. The DMD 2.0 compiler provides definitions for many Win32 API constants
and procedure definitions. Those that are not provided can
be found in Pavel "EvilOne" Minayev's WINDOWS.D, the Microsoft Windows SDK,
the Win32 API documentation, etc. Be aware there are
some differences between Pavel "EvilOne" Minayev's WINDOWS.D and
\D\dmd2\src\druntime\import\core\sys\windows\windows.d
8. Not all exported procedures are shown for brevity's sake, though they
are included in the download and are commented. In addition to
those shown, there are:
plotPoints(...)
(Plots ix[ ], iy[ ] points
in sequence specified by iOrder[ ] as a continuous curve);
plotPixels(...) (Plots
ix[ ], iy[ ] points as pixels; used for plotting 3D Strange
Attractors and Iterated nonlinear systems);
plotLines2(...)
(Plot ix[ ], iy[ ] points as series of line segments with 2 nodes
(ix[i-1], iy[i-1]) (ix[i], iy[i]), used for plotting biomorphs);
hunt (...) (Searching an ordered table); huntC (...)
(declared as extern (C), calls hunt (...), callable from
Object Pascal);
SnglRlCubcRt(...) (finds Single Real Root when a Cubic Polynomial has
one real root and two imaginary roots; calls FORTRAN functions
NROOT
in sttstcs.dll and
SIGNUM
in
mathproc.dll);
polyRoot(...) (Finds Polynomial Roots; calls FORTRAN subroutine
CUBCROOT in
mathproc.dll, may call SnglRlCubcRt(...),
SYNDIV
in mathproc.dll, and
QUADROOT
in mathproc.dll).
gFilter (...) (from an IEEE publication; Gabor filters; calls XROTATECW (...)
and YROTATECW (...) in mathproc.dll)
Also includes internal boolean functions
ftnEQVgt (...), ftnEQVge (...), and ftnEQVlt (...) -
emulates FORTRAN's logical operator .EQV.
|