How to Use the Source Code Generator

Top  Previous  Next

Source Code Generator - Detail

The Source Code Generator was designed to provide computer code to execute small or medium sized networks you build with NeuroShell 2.  It can be used for large networks, but you will probably have to do a little custom work to get the code running, because many compilers will fail to compile the large amount of code it could generate.  More on that later.

 

If you want to execute your networks from programs written to run on Microsoft Windows, then you should not use the Source Code Generator; it is much easier and faster to call the FireNet function in our Dynamic Link Library (DLL).  Refer to DLL Server - Detail for more information on calling the DLL.

 

If, however, you want to be able to call (fire) your network from a DOS program, a workstation, a mainframe, or some special purpose processor, the Source Code Generator is appropriate for you.  The source code it generates is very generic, entirely self contained, and does not contain any library calls or sophisticated constructs.  It does not even contain any looping, and thus can be transferred to almost any language easily (although the lack of looping makes it inappropriate for large networks).

 

Although it is better to call the Predict function from Excel, if you want to use the formula generated by the Source Code Generator in another spreadsheet program, it is especially convenient because the source code does not contain loops.  You will have to do some editing of the code.  The main thing you may have to watch out for, however, is to remove spaces from the formulas.  (This may be done in a word processor such as Microsoft Word.)  Some spreadsheets may stop calculating when they come to a space without giving any error or warning.

 

The Source Code Generator will generate code in C, Microsoft Visual Basic, or a very generic language we call "formulas for a calculator".  The source code generated is in the form of a subroutine called Fire_name which, like its FireNet DLL counterpart mentioned previously, takes two arguments:  the address (pointer) of a floating point array of inputs, and the address of a floating point array of outputs.  When you call the Fire_name procedure, you pass both addresses, but only the input array needs to contain any data, and it must contain the inputs. When Fire_name returns to you, it will have placed the outputs into the output array.

 

Fire_name automatically scales the inputs and outputs for you, so you will pass them the same way you would present them to NeuroShell 2.  Also, you must present them in the same order as they appeared in the columns when training.  However, if there were unused or actual output columns in between the input columns when you trained the net, you will ignore them.  If the net has 14 inputs, then the array you pass to Fire_name must have 14 cells.

 

The answers that Fire_name returns should be very close to the answers you get from NeuroShell 2, but they may differ slightly after about the 4th or 5th significant digit.  This is due to slight differences in precision, compilers, etc.

 

If you have a PNN network, remember that the answers will be the raw output neuron values, not converted to either probabilities or 0 and 1.  To convert to probabilities, add the raw neuron values for all outputs and divide each output by this sum.

 

If you have a Kohonen network, the outputs will be raw output values also, not converted to 0 or 1. Remember, if you are using the Euclidean distance metric, the winner will be the smallest distance (smallest output).

 

 

How to Use the Source Code Generator

1.  Select the Runtime Facilities module from the main NeuroShell 2 screen.

 

2.  Select Source Code Generator and a screen displays the directory and name of the configuration file (.FIG) for the current problem, as well as the name of the file which will contain the source code once it is created.  Use the File Menu to change the file names with either the Select Configuration File or Select Source Code File option.  

 

3.  Use the mouse to click on the button beside the desired type of source code:

 

C source code (which generates a file with a .C file extension)

Visual Basic source code (which generates a file with a .VB file extension)

Formulas for a calculator (which generates a .FLA file extension)

 

4.

Use the Generate Menu and select the Generate Source Code File option to create the source code.

 

 

Splitting Source Code for Large Networks

If you have a network with a large number of hidden neurons, your compiler may refuse to compile the large source code file generated.  You can probably split the source code file into several sections, each with its own procedure, compile them independently, and link them together into one program.  Then compile a primary procedure which calls each of the split procedures in turn.

 

The main difficulty will be that arrays that are defined in our source code procedure will have to be put into the primary program and made global.  Use the "extern" statement (in C) or similar statement to make sure the arrays are accessible by all of the procedures.  These arrays are the "feature" arrays.

 

The example below shows you how to split generated source code into two parts.

 

Suppose that the Source Code Generator has generated the following code in C for the Exclusive OR problem trained with PNN, no input scaling, and no Calibration feature:

 

module XOR.C

 

void Fire_XOR(double *inarray, double *outarray)

{

double feature2[4];

 

/* inarray[0] is Input1 */

/* inarray[1] is Input2 */

/* outarray[0] is XOR */

/* outarray[1] is Not_XOR */

 

feature2[0] = (inarray[0] -  1) * (inarray[0] -  1);

feature2[0] = feature2[0] + (inarray[1] -  0) * (inarray[1] -  0);

feature2[0] = exp(-feature2[0] /  .72);

 

feature2[1] = (inarray[0] -  0) * (inarray[0] -  0);

feature2[1] = feature2[1] + (inarray[1] -  1) * (inarray[1] -  1);

feature2[1] = exp(-feature2[1] /  .72);

 

feature2[2] = (inarray[0] -  0) * (inarray[0] -  0);

feature2[2] = feature2[2] + (inarray[1] -  0) * (inarray[1] -  0);

feature2[2] = exp(-feature2[2] /  .72);

 

feature2[3] = (inarray[0] -  1) * (inarray[0] -  1);

feature2[3] = feature2[3] + (inarray[1] -  1) * (inarray[1] -  1);

feature2[3] = exp(-feature2[3] /  .72);

 

outarray[0] = feature2[0];

outarray[0] = outarray[0] + feature2[1];

outarray[0] = outarray[0] /  2;

 

outarray[1] = feature2[2];

outarray[1] = outarray[1] + feature2[3];

outarray[1] = outarray[1] /  2;

 

}

 

 

Now we want to divide the module XOR.C into 3 different source code modules:  XOR_MAIN.C, XOR_MOD1.C, and XOR_MOD2.C (filenames are arbitrary).  These modules should be included in the same project.  First you will need a new primary procedure in the main module XOR_MAIN.C, we will continue to call this procedure Fire_XOR:

 

module XOR_MAIN.C

 

double feature2[4];  /* note that this has been made global */

void Fire_XOR(double *inarray, double *outarray)

{

/* inarray[0] is Input1 */

/* inarray[1] is Input2 */

/* outarray[0] is XOR */

/* outarray[1] is Not_XOR */

 

/* make the calls to the two new modules */

Fire_XOR1(inarray, outarray);

Fire_XOR2(inarray, outarray);

}

 

 

Then compile the following two new procedures Fire_XOR1 and Fire_XOR2 in separate C modules:

 

module XOR_MOD1.C

 

extern  double feature2[4];

void Fire_XOR1(double *inarray, double *outarray)

{

feature2[0] = (inarray[0] -  1) * (inarray[0] -  1);

feature2[0] = feature2[0] + (inarray[1] -  0) * (inarray[1] -  0);

feature2[0] = exp(-feature2[0] /  .72);

 

feature2[1] = (inarray[0] -  0) * (inarray[0] -  0);

feature2[1] = feature2[1] + (inarray[1] -  1) * (inarray[1] -  1);

feature2[1] = exp(-feature2[1] /  .72);

 

feature2[2] = (inarray[0] -  0) * (inarray[0] -  0);

feature2[2] = feature2[2] + (inarray[1] -  0) * (inarray[1] -  0);

feature2[2] = exp(-feature2[2] /  .72);            

}

 

 

module XOR_MOD2.C

 

extern  double feature2[4];

void Fire_XOR2(double *inarray, double *outarray)

{

feature2[3] = (inarray[0] -  1) * (inarray[0] -  1);

feature2[3] = feature2[3] + (inarray[1] -  1) * (inarray[1] -  1);

feature2[3] = exp(-feature2[3] /  .72);

 

outarray[0] = feature2[0];

outarray[0] = outarray[0] + feature2[1];

outarray[0] = outarray[0] /  2;

 

outarray[1] = feature2[2];

outarray[1] = outarray[1] + feature2[3];

outarray[1] = outarray[1] /  2;      

}

 

Here is how the original procedure Fire_XOR can be called from a module of this project:

 

double inputs[2];

double outputs[2];

 

inputs[1]=1;

inputs[2]=0;

Fire_XOR(inputs, outputs);

if (outputs[1]>outputs[2]) ....  /* the exclusive or is true */

if (outputs[1]<outputs[2]) ....  /* the exclusive or is false */

if (outputs[1]==outputs[2]) ....  /* we don't know */