>> Rodney Roberts IS & Education Professional Homepage   >> Programming Tutorials And Downloads







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)

Simple Simulated Annealing User Interface

    Files:
    (Notepad++ was used to create/edit the .d and .di files - the tabbing and spacing may be off in MS Notepad)
  1. 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.

  2. 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).

  3. 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.

  4. 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;

  5. 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.

Simple Simulated Annealing User Interface

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.

Simple Simulated Annealing Demonstration program
    Compiling/Linking:
  1. 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)
  2. 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)
  3. Prepare hedtio dll.def; Compile/Link module hedtio
  4. 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
    		  
  5. 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.)
  6. 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)
  7. 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)


  8. 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.


Any and all © copyrights, ® ™ trademarks, or other intellectual property (IP) mentioned/used here are the property of their respective owners.

Feel free to use any of the above in your project (without violating any intellectual property rights); please give credit (same idea as Copyleft).

Page best viewed with Mozilla FireFox 3.6.13 (or higher) and Google Chrome Version 40.0.2214.94 (or higher).

Free web hosting provided by:
Award Space Web Hosting Free Web Hosting , &  Free Web Hosting.



>> Rodney Roberts IS & Education Professional Homepage   >> Programming Tutorials And Downloads